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