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