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 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_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) 309 { 310 struct pfioc_table io; 311 312 if (size < 0 || (size && !tbl)) { 313 errno = EINVAL; 314 return (-1); 315 } 316 bzero(&io, sizeof io); 317 io.pfrio_flags = flags; 318 io.pfrio_buffer = tbl; 319 io.pfrio_esize = sizeof(*tbl); 320 io.pfrio_size = size; 321 if (ioctl(dev, DIOCRCLRTSTATS, &io)) 322 return (-1); 323 if (nzero) 324 *nzero = io.pfrio_nzero; 325 return (0); 326 } 327 328 int 329 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 330 int *nmatch, int flags) 331 { 332 struct pfioc_table io; 333 334 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 335 errno = EINVAL; 336 return (-1); 337 } 338 bzero(&io, sizeof io); 339 io.pfrio_flags = flags; 340 io.pfrio_table = *tbl; 341 io.pfrio_buffer = addr; 342 io.pfrio_esize = sizeof(*addr); 343 io.pfrio_size = size; 344 if (ioctl(dev, DIOCRTSTADDRS, &io)) 345 return (-1); 346 if (nmatch) 347 *nmatch = io.pfrio_nmatch; 348 return (0); 349 } 350 351 int 352 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, 353 int *nadd, int *naddr, int ticket, int flags) 354 { 355 struct pfioc_table io; 356 357 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 358 errno = EINVAL; 359 return (-1); 360 } 361 bzero(&io, sizeof io); 362 io.pfrio_flags = flags; 363 io.pfrio_table = *tbl; 364 io.pfrio_buffer = addr; 365 io.pfrio_esize = sizeof(*addr); 366 io.pfrio_size = size; 367 io.pfrio_ticket = ticket; 368 if (ioctl(dev, DIOCRINADEFINE, &io)) 369 return (-1); 370 if (nadd != NULL) 371 *nadd = io.pfrio_nadd; 372 if (naddr != NULL) 373 *naddr = io.pfrio_naddr; 374 return (0); 375 } 376 377 /* interface management code */ 378 379 int 380 pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size) 381 { 382 struct pfioc_iface io; 383 384 if (size == NULL || *size < 0 || (*size && buf == NULL)) { 385 errno = EINVAL; 386 return (-1); 387 } 388 bzero(&io, sizeof io); 389 if (filter != NULL) 390 if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >= 391 sizeof(io.pfiio_name)) { 392 errno = EINVAL; 393 return (-1); 394 } 395 io.pfiio_buffer = buf; 396 io.pfiio_esize = sizeof(*buf); 397 io.pfiio_size = *size; 398 if (ioctl(dev, DIOCIGETIFACES, &io)) 399 return (-1); 400 *size = io.pfiio_size; 401 return (0); 402 } 403 404 /* buffer management code */ 405 406 const size_t buf_esize[PFRB_MAX] = { 0, 407 sizeof(struct pfr_table), sizeof(struct pfr_tstats), 408 sizeof(struct pfr_addr), sizeof(struct pfr_astats), 409 sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e) 410 }; 411 412 /* 413 * add one element to the buffer 414 */ 415 int 416 pfr_buf_add(struct pfr_buffer *b, const void *e) 417 { 418 size_t bs; 419 420 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX || 421 e == NULL) { 422 errno = EINVAL; 423 return (-1); 424 } 425 bs = buf_esize[b->pfrb_type]; 426 if (b->pfrb_size == b->pfrb_msize) 427 if (pfr_buf_grow(b, 0)) 428 return (-1); 429 memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs); 430 b->pfrb_size++; 431 return (0); 432 } 433 434 /* 435 * return next element of the buffer (or first one if prev is NULL) 436 * see PFRB_FOREACH macro 437 */ 438 void * 439 pfr_buf_next(struct pfr_buffer *b, const void *prev) 440 { 441 size_t bs; 442 443 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) 444 return (NULL); 445 if (b->pfrb_size == 0) 446 return (NULL); 447 if (prev == NULL) 448 return (b->pfrb_caddr); 449 bs = buf_esize[b->pfrb_type]; 450 if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1) 451 return (NULL); 452 return (((caddr_t)prev) + bs); 453 } 454 455 /* 456 * minsize: 457 * 0: make the buffer somewhat bigger 458 * n: make room for "n" entries in the buffer 459 */ 460 int 461 pfr_buf_grow(struct pfr_buffer *b, int minsize) 462 { 463 caddr_t p; 464 size_t bs; 465 466 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) { 467 errno = EINVAL; 468 return (-1); 469 } 470 if (minsize != 0 && minsize <= b->pfrb_msize) 471 return (0); 472 bs = buf_esize[b->pfrb_type]; 473 if (!b->pfrb_msize) { 474 if (minsize < 64) 475 minsize = 64; 476 b->pfrb_caddr = calloc(bs, minsize); 477 if (b->pfrb_caddr == NULL) 478 return (-1); 479 b->pfrb_msize = minsize; 480 } else { 481 if (minsize == 0) 482 minsize = b->pfrb_msize * 2; 483 if (minsize < 0 || minsize >= SIZE_T_MAX / bs) { 484 /* msize overflow */ 485 errno = ENOMEM; 486 return (-1); 487 } 488 p = realloc(b->pfrb_caddr, minsize * bs); 489 if (p == NULL) 490 return (-1); 491 bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs); 492 b->pfrb_caddr = p; 493 b->pfrb_msize = minsize; 494 } 495 return (0); 496 } 497 498 /* 499 * reset buffer and free memory. 500 */ 501 void 502 pfr_buf_clear(struct pfr_buffer *b) 503 { 504 if (b == NULL) 505 return; 506 if (b->pfrb_caddr != NULL) 507 free(b->pfrb_caddr); 508 b->pfrb_caddr = NULL; 509 b->pfrb_size = b->pfrb_msize = 0; 510 } 511 512 int 513 pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork, 514 int (*append_addr)(struct pfr_buffer *, char *, int)) 515 { 516 FILE *fp; 517 char buf[BUF_SIZE]; 518 int rv; 519 520 if (file == NULL) 521 return (0); 522 if (!strcmp(file, "-")) 523 fp = stdin; 524 else { 525 fp = pfctl_fopen(file, "r"); 526 if (fp == NULL) 527 return (-1); 528 } 529 while ((rv = pfr_next_token(buf, fp)) == 1) 530 if (append_addr(b, buf, nonetwork)) { 531 rv = -1; 532 break; 533 } 534 if (fp != stdin) 535 fclose(fp); 536 return (rv); 537 } 538 539 int 540 pfr_next_token(char buf[BUF_SIZE], FILE *fp) 541 { 542 static char next_ch = ' '; 543 int i = 0; 544 545 for (;;) { 546 /* skip spaces */ 547 while (isspace(next_ch) && !feof(fp)) 548 next_ch = fgetc(fp); 549 /* remove from '#' until end of line */ 550 if (next_ch == '#') 551 while (!feof(fp)) { 552 next_ch = fgetc(fp); 553 if (next_ch == '\n') 554 break; 555 } 556 else 557 break; 558 } 559 if (feof(fp)) { 560 next_ch = ' '; 561 return (0); 562 } 563 do { 564 if (i < BUF_SIZE) 565 buf[i++] = next_ch; 566 next_ch = fgetc(fp); 567 } while (!feof(fp) && !isspace(next_ch)); 568 if (i >= BUF_SIZE) { 569 errno = EINVAL; 570 return (-1); 571 } 572 buf[i] = '\0'; 573 return (1); 574 } 575 576 char * 577 pfr_strerror(int errnum) 578 { 579 switch (errnum) { 580 case ESRCH: 581 return "Table does not exist"; 582 case ENOENT: 583 return "Anchor or Ruleset does not exist"; 584 default: 585 return strerror(errnum); 586 } 587 } 588