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