1 /* $OpenBSD: pfctl_radix.c,v 1.24 2004/02/10 18:29:30 henning Exp $ */ 2 /* $DragonFly: src/usr.sbin/pfctl/pfctl_radix.c,v 1.1 2004/09/21 21:25:28 joerg 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/pf/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_fd; 54 55 static int pfr_next_token(char buf[], 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_fd, 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_fd, 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_fd, 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_fd, 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_fd, 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_fd, 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_fd, 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_fd, 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_fd, 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_fd, 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_fd, 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_fd, 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_fd, 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_fd, 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_fd, DIOCRTSTADDRS, &io)) 390 return (-1); 391 if (nmatch) 392 *nmatch = io.pfrio_nmatch; 393 return (0); 394 } 395 396 int 397 pfr_ina_begin(struct pfr_table *trs, int *ticket, int *ndel, int flags) 398 { 399 struct pfioc_table io; 400 401 bzero(&io, sizeof io); 402 if (trs != NULL) 403 io.pfrio_table = *trs; 404 io.pfrio_flags = flags; 405 if (ioctl(dev_fd, DIOCRINABEGIN, &io)) 406 return (-1); 407 if (ndel != NULL) 408 *ndel = io.pfrio_ndel; 409 if (ticket != NULL) 410 *ticket = io.pfrio_ticket; 411 return (0); 412 } 413 414 int 415 pfr_ina_commit(struct pfr_table *trs, int ticket, int *nadd, int *nchange, 416 int flags) 417 { 418 struct pfioc_table io; 419 420 bzero(&io, sizeof io); 421 if (trs != NULL) 422 io.pfrio_table = *trs; 423 io.pfrio_flags = flags; 424 io.pfrio_ticket = ticket; 425 if (ioctl(dev_fd, DIOCRINACOMMIT, &io)) 426 return (-1); 427 if (nadd != NULL) 428 *nadd = io.pfrio_nadd; 429 if (nchange != NULL) 430 *nchange = io.pfrio_nchange; 431 return (0); 432 } 433 434 int 435 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, 436 int *nadd, int *naddr, int ticket, int flags) 437 { 438 struct pfioc_table io; 439 440 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 441 errno = EINVAL; 442 return (-1); 443 } 444 bzero(&io, sizeof io); 445 io.pfrio_flags = flags; 446 io.pfrio_table = *tbl; 447 io.pfrio_buffer = addr; 448 io.pfrio_esize = sizeof(*addr); 449 io.pfrio_size = size; 450 io.pfrio_ticket = ticket; 451 if (ioctl(dev_fd, DIOCRINADEFINE, &io)) 452 return (-1); 453 if (nadd != NULL) 454 *nadd = io.pfrio_nadd; 455 if (naddr != NULL) 456 *naddr = io.pfrio_naddr; 457 return (0); 458 } 459 460 /* interface management code */ 461 462 int 463 pfi_get_ifaces(const char *filter, struct pfi_if *buf, int *size, int flags) 464 { 465 struct pfioc_iface io; 466 467 if (size == NULL || *size < 0 || (*size && buf == NULL)) { 468 errno = EINVAL; 469 return (-1); 470 } 471 bzero(&io, sizeof io); 472 io.pfiio_flags = flags; 473 if (filter != NULL) 474 if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >= 475 sizeof(io.pfiio_name)) { 476 errno = EINVAL; 477 return (-1); 478 } 479 io.pfiio_buffer = buf; 480 io.pfiio_esize = sizeof(*buf); 481 io.pfiio_size = *size; 482 if (ioctl(dev_fd, DIOCIGETIFACES, &io)) 483 return (-1); 484 *size = io.pfiio_size; 485 return (0); 486 } 487 488 /* buffer management code */ 489 490 size_t buf_esize[PFRB_MAX] = { 0, 491 sizeof(struct pfr_table), sizeof(struct pfr_tstats), 492 sizeof(struct pfr_addr), sizeof(struct pfr_astats), 493 sizeof(struct pfi_if), sizeof(struct pfioc_trans_e) 494 }; 495 496 /* 497 * add one element to the buffer 498 */ 499 int 500 pfr_buf_add(struct pfr_buffer *b, const void *e) 501 { 502 size_t bs; 503 504 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX || 505 e == NULL) { 506 errno = EINVAL; 507 return (-1); 508 } 509 bs = buf_esize[b->pfrb_type]; 510 if (b->pfrb_size == b->pfrb_msize) 511 if (pfr_buf_grow(b, 0)) 512 return (-1); 513 memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs); 514 b->pfrb_size++; 515 return (0); 516 } 517 518 /* 519 * return next element of the buffer (or first one if prev is NULL) 520 * see PFRB_FOREACH macro 521 */ 522 const void * 523 pfr_buf_next(struct pfr_buffer *b, const void *prev) 524 { 525 size_t bs; 526 527 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) 528 return (NULL); 529 if (b->pfrb_size == 0) 530 return (NULL); 531 if (prev == NULL) 532 return (b->pfrb_caddr); 533 bs = buf_esize[b->pfrb_type]; 534 if ((((c_caddr_t)prev)-((c_caddr_t)b->pfrb_caddr)) / bs + 1 >= 535 (size_t)b->pfrb_size) 536 return (NULL); 537 return (((c_caddr_t)prev) + bs); 538 } 539 540 /* 541 * minsize: 542 * 0: make the buffer somewhat bigger 543 * n: make room for "n" entries in the buffer 544 */ 545 int 546 pfr_buf_grow(struct pfr_buffer *b, int minsize) 547 { 548 caddr_t p; 549 size_t bs; 550 551 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) { 552 errno = EINVAL; 553 return (-1); 554 } 555 if (minsize != 0 && minsize <= b->pfrb_msize) 556 return (0); 557 bs = buf_esize[b->pfrb_type]; 558 if (!b->pfrb_msize) { 559 if (minsize < 64) 560 minsize = 64; 561 b->pfrb_caddr = calloc(bs, minsize); 562 if (b->pfrb_caddr == NULL) 563 return (-1); 564 b->pfrb_msize = minsize; 565 } else { 566 if (minsize == 0) 567 minsize = b->pfrb_msize * 2; 568 if (minsize < 0 || (size_t)minsize >= SIZE_T_MAX / bs) { 569 /* msize overflow */ 570 errno = ENOMEM; 571 return (-1); 572 } 573 p = realloc(b->pfrb_caddr, minsize * bs); 574 if (p == NULL) 575 return (-1); 576 bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs); 577 b->pfrb_caddr = p; 578 b->pfrb_msize = minsize; 579 } 580 return (0); 581 } 582 583 /* 584 * reset buffer and free memory. 585 */ 586 void 587 pfr_buf_clear(struct pfr_buffer *b) 588 { 589 if (b == NULL) 590 return; 591 if (b->pfrb_caddr != NULL) 592 free(b->pfrb_caddr); 593 b->pfrb_caddr = NULL; 594 b->pfrb_size = b->pfrb_msize = 0; 595 } 596 597 int 598 pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork, 599 int (*append_addr)(struct pfr_buffer *, char *, int)) 600 { 601 FILE *fp; 602 char buf[BUF_SIZE]; 603 int rv; 604 605 if (file == NULL) 606 return (0); 607 if (!strcmp(file, "-")) 608 fp = stdin; 609 else { 610 fp = fopen(file, "r"); 611 if (fp == NULL) 612 return (-1); 613 } 614 while ((rv = pfr_next_token(buf, fp)) == 1) 615 if (append_addr(b, buf, nonetwork)) { 616 rv = -1; 617 break; 618 } 619 if (fp != stdin) 620 fclose(fp); 621 return (rv); 622 } 623 624 int 625 pfr_next_token(char buf[BUF_SIZE], FILE *fp) 626 { 627 static char next_ch = ' '; 628 int i = 0; 629 630 for (;;) { 631 /* skip spaces */ 632 while (isspace(next_ch) && !feof(fp)) 633 next_ch = fgetc(fp); 634 /* remove from '#' until end of line */ 635 if (next_ch == '#') 636 while (!feof(fp)) { 637 next_ch = fgetc(fp); 638 if (next_ch == '\n') 639 break; 640 } 641 else 642 break; 643 } 644 if (feof(fp)) { 645 next_ch = ' '; 646 return (0); 647 } 648 do { 649 if (i < BUF_SIZE) 650 buf[i++] = next_ch; 651 next_ch = fgetc(fp); 652 } while (!feof(fp) && !isspace(next_ch)); 653 if (i >= BUF_SIZE) { 654 errno = EINVAL; 655 return (-1); 656 } 657 buf[i] = '\0'; 658 return (1); 659 } 660 661 const char * 662 pfr_strerror(int errnum) 663 { 664 switch (errnum) { 665 case ESRCH: 666 return "Table does not exist"; 667 case ENOENT: 668 return "Anchor or Ruleset does not exist"; 669 default: 670 return strerror(errnum); 671 } 672 } 673