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 55 extern int dev; 56 57 static int pfr_next_token(char buf[], FILE *); 58 59 60 int 61 pfr_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 76 int 77 pfr_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 97 int 98 pfr_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 118 int 119 pfr_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 141 int 142 pfr_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 164 int 165 pfr_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 183 int 184 pfr_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 206 int 207 pfr_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 229 int 230 pfr_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 259 int 260 pfr_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 282 int 283 pfr_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 305 int 306 pfr_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 326 int 327 pfr_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 349 int 350 pfr_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 377 int 378 pfi_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 404 size_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 */ 413 int 414 pfr_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 */ 436 void * 437 pfr_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 */ 458 int 459 pfr_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 */ 499 void 500 pfr_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 510 int 511 pfr_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 537 int 538 pfr_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 574 char * 575 pfr_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