1 /* $OpenBSD: pfctl_radix.c,v 1.40 2024/11/20 13:57:29 kirill Exp $ */ 2 3 /* 4 * Copyright (c) 2002 Cedric Berger 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 * 31 */ 32 33 #include <sys/types.h> 34 #include <sys/ioctl.h> 35 #include <sys/socket.h> 36 37 #include <netinet/in.h> 38 #include <net/if.h> 39 #include <net/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 #include "pfctl_parser.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 struct pfr_ktablehead pfr_ktables = { 0 }; 59 RB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); 60 61 int 62 pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q) 63 { 64 int d; 65 66 if ((d = strncmp(p->pfrkt_name, q->pfrkt_name, PF_TABLE_NAME_SIZE))) 67 return (d); 68 return (strcmp(p->pfrkt_anchor, q->pfrkt_anchor)); 69 } 70 71 int 72 pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags) 73 { 74 struct pfioc_table io; 75 76 bzero(&io, sizeof io); 77 io.pfrio_flags = flags; 78 if (filter != NULL) 79 io.pfrio_table = *filter; 80 if (ioctl(dev, DIOCRCLRTABLES, &io) == -1) 81 return (-1); 82 if (ndel != NULL) 83 *ndel = io.pfrio_ndel; 84 return (0); 85 } 86 87 int 88 pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) 89 { 90 struct pfioc_table io; 91 92 if (size < 0 || (size && tbl == NULL)) { 93 errno = EINVAL; 94 return (-1); 95 } 96 bzero(&io, sizeof io); 97 io.pfrio_flags = flags; 98 io.pfrio_buffer = tbl; 99 io.pfrio_esize = sizeof(*tbl); 100 io.pfrio_size = size; 101 if (ioctl(dev, DIOCRADDTABLES, &io) == -1) 102 return (-1); 103 if (nadd != NULL) 104 *nadd = io.pfrio_nadd; 105 return (0); 106 } 107 108 int 109 pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags) 110 { 111 struct pfioc_table io; 112 113 if (size < 0 || (size && tbl == NULL)) { 114 errno = EINVAL; 115 return (-1); 116 } 117 bzero(&io, sizeof io); 118 io.pfrio_flags = flags; 119 io.pfrio_buffer = tbl; 120 io.pfrio_esize = sizeof(*tbl); 121 io.pfrio_size = size; 122 if (ioctl(dev, DIOCRDELTABLES, &io) == -1) 123 return (-1); 124 if (ndel != NULL) 125 *ndel = io.pfrio_ndel; 126 return (0); 127 } 128 129 int 130 pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, 131 int flags) 132 { 133 struct pfioc_table io; 134 135 if (size == NULL || *size < 0 || (*size && tbl == NULL)) { 136 errno = EINVAL; 137 return (-1); 138 } 139 bzero(&io, sizeof io); 140 io.pfrio_flags = flags; 141 if (filter != NULL) 142 io.pfrio_table = *filter; 143 io.pfrio_buffer = tbl; 144 io.pfrio_esize = sizeof(*tbl); 145 io.pfrio_size = *size; 146 if (ioctl(dev, DIOCRGETTABLES, &io) == -1) 147 return (-1); 148 *size = io.pfrio_size; 149 return (0); 150 } 151 152 int 153 pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, 154 int flags) 155 { 156 struct pfioc_table io; 157 158 if (size == NULL || *size < 0 || (*size && tbl == NULL)) { 159 errno = EINVAL; 160 return (-1); 161 } 162 bzero(&io, sizeof io); 163 io.pfrio_flags = flags; 164 if (filter != NULL) 165 io.pfrio_table = *filter; 166 io.pfrio_buffer = tbl; 167 io.pfrio_esize = sizeof(*tbl); 168 io.pfrio_size = *size; 169 if (ioctl(dev, DIOCRGETTSTATS, &io) == -1) 170 return (-1); 171 *size = io.pfrio_size; 172 return (0); 173 } 174 175 int 176 pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) 177 { 178 struct pfioc_table io; 179 180 if (tbl == NULL) { 181 errno = EINVAL; 182 return (-1); 183 } 184 bzero(&io, sizeof io); 185 io.pfrio_flags = flags; 186 io.pfrio_table = *tbl; 187 if (ioctl(dev, DIOCRCLRADDRS, &io) == -1) 188 return (-1); 189 if (ndel != NULL) 190 *ndel = io.pfrio_ndel; 191 return (0); 192 } 193 194 int 195 pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 196 int *nadd, int flags) 197 { 198 struct pfioc_table io; 199 200 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 201 errno = EINVAL; 202 return (-1); 203 } 204 bzero(&io, sizeof io); 205 io.pfrio_flags = flags; 206 io.pfrio_table = *tbl; 207 io.pfrio_buffer = addr; 208 io.pfrio_esize = sizeof(*addr); 209 io.pfrio_size = size; 210 if (ioctl(dev, DIOCRADDADDRS, &io) == -1) 211 return (-1); 212 if (nadd != NULL) 213 *nadd = io.pfrio_nadd; 214 return (0); 215 } 216 217 int 218 pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 219 int *ndel, int flags) 220 { 221 struct pfioc_table io; 222 223 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 224 errno = EINVAL; 225 return (-1); 226 } 227 bzero(&io, sizeof io); 228 io.pfrio_flags = flags; 229 io.pfrio_table = *tbl; 230 io.pfrio_buffer = addr; 231 io.pfrio_esize = sizeof(*addr); 232 io.pfrio_size = size; 233 if (ioctl(dev, DIOCRDELADDRS, &io) == -1) 234 return (-1); 235 if (ndel != NULL) 236 *ndel = io.pfrio_ndel; 237 return (0); 238 } 239 240 int 241 pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 242 int *size2, int *nadd, int *ndel, int *nchange, int flags) 243 { 244 struct pfioc_table io; 245 246 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 247 errno = EINVAL; 248 return (-1); 249 } 250 bzero(&io, sizeof io); 251 io.pfrio_flags = flags; 252 io.pfrio_table = *tbl; 253 io.pfrio_buffer = addr; 254 io.pfrio_esize = sizeof(*addr); 255 io.pfrio_size = size; 256 io.pfrio_size2 = (size2 != NULL) ? *size2 : 0; 257 if (ioctl(dev, DIOCRSETADDRS, &io) == -1) 258 return (-1); 259 if (nadd != NULL) 260 *nadd = io.pfrio_nadd; 261 if (ndel != NULL) 262 *ndel = io.pfrio_ndel; 263 if (nchange != NULL) 264 *nchange = io.pfrio_nchange; 265 if (size2 != NULL) 266 *size2 = io.pfrio_size2; 267 return (0); 268 } 269 270 int 271 pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, 272 int flags) 273 { 274 struct pfioc_table io; 275 276 if (tbl == NULL || size == NULL || *size < 0 || 277 (*size && addr == NULL)) { 278 errno = EINVAL; 279 return (-1); 280 } 281 bzero(&io, sizeof io); 282 io.pfrio_flags = flags; 283 io.pfrio_table = *tbl; 284 io.pfrio_buffer = addr; 285 io.pfrio_esize = sizeof(*addr); 286 io.pfrio_size = *size; 287 if (ioctl(dev, DIOCRGETADDRS, &io) == -1) 288 return (-1); 289 *size = io.pfrio_size; 290 return (0); 291 } 292 293 int 294 pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, 295 int flags) 296 { 297 struct pfioc_table io; 298 299 if (tbl == NULL || size == NULL || *size < 0 || 300 (*size && addr == NULL)) { 301 errno = EINVAL; 302 return (-1); 303 } 304 bzero(&io, sizeof io); 305 io.pfrio_flags = flags; 306 io.pfrio_table = *tbl; 307 io.pfrio_buffer = addr; 308 io.pfrio_esize = sizeof(*addr); 309 io.pfrio_size = *size; 310 if (ioctl(dev, DIOCRGETASTATS, &io) == -1) 311 return (-1); 312 *size = io.pfrio_size; 313 return (0); 314 } 315 316 int 317 pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, 318 int *nzero, int flags) 319 { 320 struct pfioc_table io; 321 322 if (size < 0 || (size && !tbl) || addr == NULL) { 323 errno = EINVAL; 324 return (-1); 325 } 326 bzero(&io, sizeof io); 327 io.pfrio_flags = flags; 328 io.pfrio_table = *tbl; 329 io.pfrio_buffer = addr; 330 io.pfrio_esize = sizeof(*addr); 331 io.pfrio_size = size; 332 if (ioctl(dev, DIOCRCLRASTATS, &io) == -1) 333 return (-1); 334 if (nzero) 335 *nzero = io.pfrio_nzero; 336 return (0); 337 } 338 339 int 340 pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) 341 { 342 struct pfioc_table io; 343 344 if (size < 0 || (size && !tbl)) { 345 errno = EINVAL; 346 return (-1); 347 } 348 bzero(&io, sizeof io); 349 io.pfrio_flags = flags; 350 io.pfrio_buffer = tbl; 351 io.pfrio_esize = sizeof(*tbl); 352 io.pfrio_size = size; 353 if (ioctl(dev, DIOCRCLRTSTATS, &io) == -1) 354 return (-1); 355 if (nzero) 356 *nzero = io.pfrio_nzero; 357 return (0); 358 } 359 360 int 361 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 362 int *nmatch, 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 if (ioctl(dev, DIOCRTSTADDRS, &io) == -1) 377 return (-1); 378 if (nmatch) 379 *nmatch = io.pfrio_nmatch; 380 return (0); 381 } 382 383 int 384 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, 385 int *nadd, int *naddr, int ticket, int flags) 386 { 387 struct pfioc_table io; 388 389 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 390 DBGPRINT("%s %p %d %p\n", __func__, tbl, size, addr); 391 errno = EINVAL; 392 return (-1); 393 } 394 bzero(&io, sizeof io); 395 io.pfrio_flags = flags; 396 io.pfrio_table = *tbl; 397 io.pfrio_buffer = addr; 398 io.pfrio_esize = sizeof(*addr); 399 io.pfrio_size = size; 400 io.pfrio_ticket = ticket; 401 if (ioctl(dev, DIOCRINADEFINE, &io) == -1) 402 return (-1); 403 if (nadd != NULL) 404 *nadd = io.pfrio_nadd; 405 if (naddr != NULL) 406 *naddr = io.pfrio_naddr; 407 return (0); 408 } 409 410 /* interface management code */ 411 412 int 413 pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size) 414 { 415 struct pfioc_iface io; 416 417 if (size == NULL || *size < 0 || (*size && buf == NULL)) { 418 errno = EINVAL; 419 return (-1); 420 } 421 bzero(&io, sizeof io); 422 if (filter != NULL) 423 if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >= 424 sizeof(io.pfiio_name)) { 425 errno = EINVAL; 426 return (-1); 427 } 428 io.pfiio_buffer = buf; 429 io.pfiio_esize = sizeof(*buf); 430 io.pfiio_size = *size; 431 if (ioctl(dev, DIOCIGETIFACES, &io) == -1) 432 return (-1); 433 *size = io.pfiio_size; 434 return (0); 435 } 436 437 /* buffer management code */ 438 439 size_t buf_esize[PFRB_MAX] = { 0, 440 sizeof(struct pfr_table), sizeof(struct pfr_tstats), 441 sizeof(struct pfr_addr), sizeof(struct pfr_astats), 442 sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e) 443 }; 444 445 /* 446 * add one element to the buffer 447 */ 448 int 449 pfr_buf_add(struct pfr_buffer *b, const void *e) 450 { 451 size_t bs; 452 453 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX || 454 e == NULL) { 455 errno = EINVAL; 456 return (-1); 457 } 458 bs = buf_esize[b->pfrb_type]; 459 if (b->pfrb_size == b->pfrb_msize) 460 if (pfr_buf_grow(b, 0)) 461 return (-1); 462 memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs); 463 b->pfrb_size++; 464 return (0); 465 } 466 467 /* 468 * return next element of the buffer (or first one if prev is NULL) 469 * see PFRB_FOREACH macro 470 */ 471 void * 472 pfr_buf_next(struct pfr_buffer *b, const void *prev) 473 { 474 size_t bs; 475 476 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) 477 return (NULL); 478 if (b->pfrb_size == 0) 479 return (NULL); 480 if (prev == NULL) 481 return (b->pfrb_caddr); 482 bs = buf_esize[b->pfrb_type]; 483 if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1) 484 return (NULL); 485 return (((caddr_t)prev) + bs); 486 } 487 488 /* 489 * minsize: 490 * 0: make the buffer somewhat bigger 491 * n: make room for "n" entries in the buffer 492 */ 493 int 494 pfr_buf_grow(struct pfr_buffer *b, int minsize) 495 { 496 caddr_t p; 497 size_t bs; 498 499 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) { 500 errno = EINVAL; 501 return (-1); 502 } 503 if (minsize != 0 && minsize <= b->pfrb_msize) 504 return (0); 505 bs = buf_esize[b->pfrb_type]; 506 if (!b->pfrb_msize) { 507 if (minsize < 64) 508 minsize = 64; 509 } 510 if (minsize == 0) 511 minsize = b->pfrb_msize * 2; 512 p = reallocarray(b->pfrb_caddr, minsize, bs); 513 if (p == NULL) 514 return (-1); 515 bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs); 516 b->pfrb_caddr = p; 517 b->pfrb_msize = minsize; 518 return (0); 519 } 520 521 /* 522 * reset buffer and free memory. 523 */ 524 void 525 pfr_buf_clear(struct pfr_buffer *b) 526 { 527 if (b == NULL) 528 return; 529 free(b->pfrb_caddr); 530 b->pfrb_caddr = NULL; 531 b->pfrb_size = b->pfrb_msize = 0; 532 } 533 534 int 535 pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork, int opts) 536 { 537 FILE *fp; 538 char buf[BUF_SIZE]; 539 int rv; 540 int ev = 0; 541 542 if (file == NULL) 543 return (0); 544 if (!strcmp(file, "-")) 545 fp = stdin; 546 else { 547 fp = pfctl_fopen(file, "r"); 548 if (fp == NULL) 549 return (-1); 550 } 551 while ((rv = pfr_next_token(buf, fp)) == 1) 552 if ((ev = append_addr(b, buf, nonetwork, opts)) == -1) { 553 rv = -1; 554 break; 555 } 556 if (ev == 1) /* expected further append_addr call */ 557 rv = -1; 558 if (fp != stdin) 559 fclose(fp); 560 return (rv); 561 } 562 563 int 564 pfr_next_token(char buf[BUF_SIZE], FILE *fp) 565 { 566 static char next_ch = ' '; 567 int i = 0; 568 569 for (;;) { 570 /* skip spaces */ 571 while (isspace((unsigned char)next_ch) && !feof(fp)) 572 next_ch = fgetc(fp); 573 /* remove from '#' until end of line */ 574 if (next_ch == '#') 575 while (!feof(fp)) { 576 next_ch = fgetc(fp); 577 if (next_ch == '\n') 578 break; 579 } 580 else 581 break; 582 } 583 if (feof(fp)) { 584 next_ch = ' '; 585 return (0); 586 } 587 do { 588 if (i < BUF_SIZE) 589 buf[i++] = next_ch; 590 next_ch = fgetc(fp); 591 } while (!feof(fp) && !isspace((unsigned char)next_ch)); 592 if (i >= BUF_SIZE) { 593 errno = EINVAL; 594 return (-1); 595 } 596 buf[i] = '\0'; 597 return (1); 598 } 599