1 /* $NetBSD: pfctl_radix.c,v 1.4 2004/11/14 11:26:48 yamt Exp $ */ 2 /* $OpenBSD: pfctl_radix.c,v 1.26 2004/06/14 20:44:22 cedric 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 #ifdef __NetBSD__ 39 #include <netinet/in.h> 40 #endif 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 62 int 63 pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags) 64 { 65 struct pfioc_table io; 66 67 bzero(&io, sizeof io); 68 io.pfrio_flags = flags; 69 if (filter != NULL) 70 io.pfrio_table = *filter; 71 if (ioctl(dev, DIOCRCLRTABLES, &io)) 72 return (-1); 73 if (ndel != NULL) 74 *ndel = io.pfrio_ndel; 75 return (0); 76 } 77 78 int 79 pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) 80 { 81 struct pfioc_table io; 82 83 if (size < 0 || (size && tbl == NULL)) { 84 errno = EINVAL; 85 return (-1); 86 } 87 bzero(&io, sizeof io); 88 io.pfrio_flags = flags; 89 io.pfrio_buffer = tbl; 90 io.pfrio_esize = sizeof(*tbl); 91 io.pfrio_size = size; 92 if (ioctl(dev, DIOCRADDTABLES, &io)) 93 return (-1); 94 if (nadd != NULL) 95 *nadd = io.pfrio_nadd; 96 return (0); 97 } 98 99 int 100 pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags) 101 { 102 struct pfioc_table io; 103 104 if (size < 0 || (size && tbl == NULL)) { 105 errno = EINVAL; 106 return (-1); 107 } 108 bzero(&io, sizeof io); 109 io.pfrio_flags = flags; 110 io.pfrio_buffer = tbl; 111 io.pfrio_esize = sizeof(*tbl); 112 io.pfrio_size = size; 113 if (ioctl(dev, DIOCRDELTABLES, &io)) 114 return (-1); 115 if (ndel != NULL) 116 *ndel = io.pfrio_ndel; 117 return (0); 118 } 119 120 int 121 pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, 122 int flags) 123 { 124 struct pfioc_table io; 125 126 if (size == NULL || *size < 0 || (*size && tbl == NULL)) { 127 errno = EINVAL; 128 return (-1); 129 } 130 bzero(&io, sizeof io); 131 io.pfrio_flags = flags; 132 if (filter != NULL) 133 io.pfrio_table = *filter; 134 io.pfrio_buffer = tbl; 135 io.pfrio_esize = sizeof(*tbl); 136 io.pfrio_size = *size; 137 if (ioctl(dev, DIOCRGETTABLES, &io)) 138 return (-1); 139 *size = io.pfrio_size; 140 return (0); 141 } 142 143 int 144 pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, 145 int flags) 146 { 147 struct pfioc_table io; 148 149 if (size == NULL || *size < 0 || (*size && tbl == NULL)) { 150 errno = EINVAL; 151 return (-1); 152 } 153 bzero(&io, sizeof io); 154 io.pfrio_flags = flags; 155 if (filter != NULL) 156 io.pfrio_table = *filter; 157 io.pfrio_buffer = tbl; 158 io.pfrio_esize = sizeof(*tbl); 159 io.pfrio_size = *size; 160 if (ioctl(dev, DIOCRGETTSTATS, &io)) 161 return (-1); 162 *size = io.pfrio_size; 163 return (0); 164 } 165 166 int 167 pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) 168 { 169 struct pfioc_table io; 170 171 if (tbl == NULL) { 172 errno = EINVAL; 173 return (-1); 174 } 175 bzero(&io, sizeof io); 176 io.pfrio_flags = flags; 177 io.pfrio_table = *tbl; 178 if (ioctl(dev, DIOCRCLRADDRS, &io)) 179 return (-1); 180 if (ndel != NULL) 181 *ndel = io.pfrio_ndel; 182 return (0); 183 } 184 185 int 186 pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 187 int *nadd, int flags) 188 { 189 struct pfioc_table io; 190 191 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 192 errno = EINVAL; 193 return (-1); 194 } 195 bzero(&io, sizeof io); 196 io.pfrio_flags = flags; 197 io.pfrio_table = *tbl; 198 io.pfrio_buffer = addr; 199 io.pfrio_esize = sizeof(*addr); 200 io.pfrio_size = size; 201 if (ioctl(dev, DIOCRADDADDRS, &io)) 202 return (-1); 203 if (nadd != NULL) 204 *nadd = io.pfrio_nadd; 205 return (0); 206 } 207 208 int 209 pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 210 int *ndel, int flags) 211 { 212 struct pfioc_table io; 213 214 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 215 errno = EINVAL; 216 return (-1); 217 } 218 bzero(&io, sizeof io); 219 io.pfrio_flags = flags; 220 io.pfrio_table = *tbl; 221 io.pfrio_buffer = addr; 222 io.pfrio_esize = sizeof(*addr); 223 io.pfrio_size = size; 224 if (ioctl(dev, DIOCRDELADDRS, &io)) 225 return (-1); 226 if (ndel != NULL) 227 *ndel = io.pfrio_ndel; 228 return (0); 229 } 230 231 int 232 pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 233 int *size2, int *nadd, int *ndel, int *nchange, int flags) 234 { 235 struct pfioc_table io; 236 237 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 238 errno = EINVAL; 239 return (-1); 240 } 241 bzero(&io, sizeof io); 242 io.pfrio_flags = flags; 243 io.pfrio_table = *tbl; 244 io.pfrio_buffer = addr; 245 io.pfrio_esize = sizeof(*addr); 246 io.pfrio_size = size; 247 io.pfrio_size2 = (size2 != NULL) ? *size2 : 0; 248 if (ioctl(dev, DIOCRSETADDRS, &io)) 249 return (-1); 250 if (nadd != NULL) 251 *nadd = io.pfrio_nadd; 252 if (ndel != NULL) 253 *ndel = io.pfrio_ndel; 254 if (nchange != NULL) 255 *nchange = io.pfrio_nchange; 256 if (size2 != NULL) 257 *size2 = io.pfrio_size2; 258 return (0); 259 } 260 261 int 262 pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, 263 int flags) 264 { 265 struct pfioc_table io; 266 267 if (tbl == NULL || size == NULL || *size < 0 || 268 (*size && addr == NULL)) { 269 errno = EINVAL; 270 return (-1); 271 } 272 bzero(&io, sizeof io); 273 io.pfrio_flags = flags; 274 io.pfrio_table = *tbl; 275 io.pfrio_buffer = addr; 276 io.pfrio_esize = sizeof(*addr); 277 io.pfrio_size = *size; 278 if (ioctl(dev, DIOCRGETADDRS, &io)) 279 return (-1); 280 *size = io.pfrio_size; 281 return (0); 282 } 283 284 int 285 pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, 286 int flags) 287 { 288 struct pfioc_table io; 289 290 if (tbl == NULL || size == NULL || *size < 0 || 291 (*size && addr == NULL)) { 292 errno = EINVAL; 293 return (-1); 294 } 295 bzero(&io, sizeof io); 296 io.pfrio_flags = flags; 297 io.pfrio_table = *tbl; 298 io.pfrio_buffer = addr; 299 io.pfrio_esize = sizeof(*addr); 300 io.pfrio_size = *size; 301 if (ioctl(dev, DIOCRGETASTATS, &io)) 302 return (-1); 303 *size = io.pfrio_size; 304 return (0); 305 } 306 307 int 308 pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, 309 int *nzero, int flags) 310 { 311 struct pfioc_table io; 312 313 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 314 errno = EINVAL; 315 return (-1); 316 } 317 bzero(&io, sizeof io); 318 io.pfrio_flags = flags; 319 io.pfrio_table = *tbl; 320 io.pfrio_buffer = addr; 321 io.pfrio_esize = sizeof(*addr); 322 io.pfrio_size = size; 323 if (ioctl(dev, DIOCRCLRASTATS, &io)) 324 return (-1); 325 if (nzero != NULL) 326 *nzero = io.pfrio_nzero; 327 return (0); 328 } 329 330 int 331 pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) 332 { 333 struct pfioc_table io; 334 335 if (size < 0 || (size && !tbl)) { 336 errno = EINVAL; 337 return (-1); 338 } 339 bzero(&io, sizeof io); 340 io.pfrio_flags = flags; 341 io.pfrio_buffer = tbl; 342 io.pfrio_esize = sizeof(*tbl); 343 io.pfrio_size = size; 344 if (ioctl(dev, DIOCRCLRTSTATS, &io)) 345 return (-1); 346 if (nzero) 347 *nzero = io.pfrio_nzero; 348 return (0); 349 } 350 351 int 352 pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag, 353 int *nchange, int *ndel, int flags) 354 { 355 struct pfioc_table io; 356 357 if (size < 0 || (size && !tbl)) { 358 errno = EINVAL; 359 return (-1); 360 } 361 bzero(&io, sizeof io); 362 io.pfrio_flags = flags; 363 io.pfrio_buffer = tbl; 364 io.pfrio_esize = sizeof(*tbl); 365 io.pfrio_size = size; 366 io.pfrio_setflag = setflag; 367 io.pfrio_clrflag = clrflag; 368 if (ioctl(dev, DIOCRSETTFLAGS, &io)) 369 return (-1); 370 if (nchange) 371 *nchange = io.pfrio_nchange; 372 if (ndel) 373 *ndel = io.pfrio_ndel; 374 return (0); 375 } 376 377 int 378 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 379 int *nmatch, int flags) 380 { 381 struct pfioc_table io; 382 383 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 384 errno = EINVAL; 385 return (-1); 386 } 387 bzero(&io, sizeof io); 388 io.pfrio_flags = flags; 389 io.pfrio_table = *tbl; 390 io.pfrio_buffer = addr; 391 io.pfrio_esize = sizeof(*addr); 392 io.pfrio_size = size; 393 if (ioctl(dev, DIOCRTSTADDRS, &io)) 394 return (-1); 395 if (nmatch) 396 *nmatch = io.pfrio_nmatch; 397 return (0); 398 } 399 400 int 401 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, 402 int *nadd, int *naddr, int ticket, int flags) 403 { 404 struct pfioc_table io; 405 406 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 407 errno = EINVAL; 408 return (-1); 409 } 410 bzero(&io, sizeof io); 411 io.pfrio_flags = flags; 412 io.pfrio_table = *tbl; 413 io.pfrio_buffer = addr; 414 io.pfrio_esize = sizeof(*addr); 415 io.pfrio_size = size; 416 io.pfrio_ticket = ticket; 417 if (ioctl(dev, DIOCRINADEFINE, &io)) 418 return (-1); 419 if (nadd != NULL) 420 *nadd = io.pfrio_nadd; 421 if (naddr != NULL) 422 *naddr = io.pfrio_naddr; 423 return (0); 424 } 425 426 /* interface management code */ 427 428 int 429 pfi_get_ifaces(const char *filter, struct pfi_if *buf, int *size, int flags) 430 { 431 struct pfioc_iface io; 432 433 if (size == NULL || *size < 0 || (*size && buf == NULL)) { 434 errno = EINVAL; 435 return (-1); 436 } 437 bzero(&io, sizeof io); 438 io.pfiio_flags = flags; 439 if (filter != NULL) 440 if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >= 441 sizeof(io.pfiio_name)) { 442 errno = EINVAL; 443 return (-1); 444 } 445 io.pfiio_buffer = buf; 446 io.pfiio_esize = sizeof(*buf); 447 io.pfiio_size = *size; 448 if (ioctl(dev, DIOCIGETIFACES, &io)) 449 return (-1); 450 *size = io.pfiio_size; 451 return (0); 452 } 453 454 /* buffer management code */ 455 456 size_t buf_esize[PFRB_MAX] = { 0, 457 sizeof(struct pfr_table), sizeof(struct pfr_tstats), 458 sizeof(struct pfr_addr), sizeof(struct pfr_astats), 459 sizeof(struct pfi_if), sizeof(struct pfioc_trans_e) 460 }; 461 462 /* 463 * add one element to the buffer 464 */ 465 int 466 pfr_buf_add(struct pfr_buffer *b, const void *e) 467 { 468 size_t bs; 469 470 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX || 471 e == NULL) { 472 errno = EINVAL; 473 return (-1); 474 } 475 bs = buf_esize[b->pfrb_type]; 476 if (b->pfrb_size == b->pfrb_msize) 477 if (pfr_buf_grow(b, 0)) 478 return (-1); 479 memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs); 480 b->pfrb_size++; 481 return (0); 482 } 483 484 /* 485 * return next element of the buffer (or first one if prev is NULL) 486 * see PFRB_FOREACH macro 487 */ 488 void * 489 pfr_buf_next(struct pfr_buffer *b, const void *prev) 490 { 491 size_t bs; 492 493 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) 494 return (NULL); 495 if (b->pfrb_size == 0) 496 return (NULL); 497 if (prev == NULL) 498 return (b->pfrb_caddr); 499 bs = buf_esize[b->pfrb_type]; 500 if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1) 501 return (NULL); 502 return (((caddr_t)prev) + bs); 503 } 504 505 /* 506 * minsize: 507 * 0: make the buffer somewhat bigger 508 * n: make room for "n" entries in the buffer 509 */ 510 int 511 pfr_buf_grow(struct pfr_buffer *b, int minsize) 512 { 513 caddr_t p; 514 size_t bs; 515 516 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) { 517 errno = EINVAL; 518 return (-1); 519 } 520 if (minsize != 0 && minsize <= b->pfrb_msize) 521 return (0); 522 bs = buf_esize[b->pfrb_type]; 523 if (!b->pfrb_msize) { 524 if (minsize < 64) 525 minsize = 64; 526 b->pfrb_caddr = calloc(bs, minsize); 527 if (b->pfrb_caddr == NULL) 528 return (-1); 529 b->pfrb_msize = minsize; 530 } else { 531 if (minsize == 0) 532 minsize = b->pfrb_msize * 2; 533 if (minsize < 0 || minsize >= SIZE_T_MAX / bs) { 534 /* msize overflow */ 535 errno = ENOMEM; 536 return (-1); 537 } 538 p = realloc(b->pfrb_caddr, minsize * bs); 539 if (p == NULL) 540 return (-1); 541 bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs); 542 b->pfrb_caddr = p; 543 b->pfrb_msize = minsize; 544 } 545 return (0); 546 } 547 548 /* 549 * reset buffer and free memory. 550 */ 551 void 552 pfr_buf_clear(struct pfr_buffer *b) 553 { 554 if (b == NULL) 555 return; 556 if (b->pfrb_caddr != NULL) 557 free(b->pfrb_caddr); 558 b->pfrb_caddr = NULL; 559 b->pfrb_size = b->pfrb_msize = 0; 560 } 561 562 int 563 pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork, 564 int (*append_addr)(struct pfr_buffer *, char *, int)) 565 { 566 FILE *fp; 567 char buf[BUF_SIZE]; 568 int rv; 569 570 if (file == NULL) 571 return (0); 572 if (!strcmp(file, "-")) 573 fp = stdin; 574 else { 575 fp = pfctl_fopen(file, "r"); 576 if (fp == NULL) 577 return (-1); 578 } 579 while ((rv = pfr_next_token(buf, fp)) == 1) 580 if (append_addr(b, buf, nonetwork)) { 581 rv = -1; 582 break; 583 } 584 if (fp != stdin) 585 fclose(fp); 586 return (rv); 587 } 588 589 int 590 pfr_next_token(char buf[BUF_SIZE], FILE *fp) 591 { 592 static char next_ch = ' '; 593 int i = 0; 594 595 for (;;) { 596 /* skip spaces */ 597 while (isspace((unsigned char)next_ch) && !feof(fp)) 598 next_ch = fgetc(fp); 599 /* remove from '#' until end of line */ 600 if (next_ch == '#') 601 while (!feof(fp)) { 602 next_ch = fgetc(fp); 603 if (next_ch == '\n') 604 break; 605 } 606 else 607 break; 608 } 609 if (feof(fp)) { 610 next_ch = ' '; 611 return (0); 612 } 613 do { 614 if (i < BUF_SIZE) 615 buf[i++] = next_ch; 616 next_ch = fgetc(fp); 617 } while (!feof(fp) && !isspace((unsigned char)next_ch)); 618 if (i >= BUF_SIZE) { 619 errno = EINVAL; 620 return (-1); 621 } 622 buf[i] = '\0'; 623 return (1); 624 } 625 626 char * 627 pfr_strerror(int errnum) 628 { 629 switch (errnum) { 630 case ESRCH: 631 return "Table does not exist"; 632 case ENOENT: 633 return "Anchor or Ruleset does not exist"; 634 default: 635 return strerror(errnum); 636 } 637 } 638