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