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