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_add_table(struct pfr_table *tbl, int *nadd, int flags) 78 { 79 return (pfctl_add_table(pfh, tbl, nadd, flags)); 80 } 81 82 int 83 pfr_del_table(struct pfr_table *tbl, int *ndel, int flags) 84 { 85 return (pfctl_del_table(pfh, tbl, ndel, flags)); 86 } 87 88 int 89 pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, 90 int flags) 91 { 92 struct pfioc_table io; 93 94 if (size == NULL || *size < 0 || (*size && tbl == NULL)) { 95 errno = EINVAL; 96 return (-1); 97 } 98 bzero(&io, sizeof io); 99 io.pfrio_flags = flags; 100 if (filter != NULL) 101 io.pfrio_table = *filter; 102 io.pfrio_buffer = tbl; 103 io.pfrio_esize = sizeof(*tbl); 104 io.pfrio_size = *size; 105 if (ioctl(dev, DIOCRGETTABLES, &io)) { 106 pfr_report_error(tbl, &io, "get table"); 107 return (-1); 108 } 109 *size = io.pfrio_size; 110 return (0); 111 } 112 113 int 114 pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) 115 { 116 struct pfioc_table io; 117 118 if (tbl == NULL) { 119 errno = EINVAL; 120 return (-1); 121 } 122 bzero(&io, sizeof io); 123 io.pfrio_flags = flags; 124 io.pfrio_table = *tbl; 125 if (ioctl(dev, DIOCRCLRADDRS, &io)) 126 return (-1); 127 if (ndel != NULL) 128 *ndel = io.pfrio_ndel; 129 return (0); 130 } 131 132 int 133 pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 134 int *nadd, int flags) 135 { 136 int ret; 137 138 ret = pfctl_table_add_addrs(dev, tbl, addr, size, nadd, flags); 139 if (ret) { 140 errno = ret; 141 return (-1); 142 } 143 return (0); 144 } 145 146 int 147 pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 148 int *ndel, int flags) 149 { 150 int ret; 151 152 ret = pfctl_table_del_addrs(dev, tbl, addr, size, ndel, flags); 153 if (ret) { 154 errno = ret; 155 return (-1); 156 } 157 return (0); 158 } 159 160 int 161 pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 162 int *size2, int *nadd, int *ndel, int *nchange, int flags) 163 { 164 int ret; 165 166 ret = pfctl_table_set_addrs(dev, tbl, addr, size, size2, nadd, ndel, 167 nchange, flags); 168 if (ret) { 169 errno = ret; 170 return (-1); 171 } 172 return (0); 173 } 174 175 int 176 pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, 177 int flags) 178 { 179 int ret; 180 181 ret = pfctl_table_get_addrs(dev, tbl, addr, size, flags); 182 if (ret) { 183 errno = ret; 184 return (-1); 185 } 186 return (0); 187 } 188 189 int 190 pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, 191 int flags) 192 { 193 struct pfioc_table io; 194 195 if (tbl == NULL || size == NULL || *size < 0 || 196 (*size && addr == NULL)) { 197 errno = EINVAL; 198 return (-1); 199 } 200 bzero(&io, sizeof io); 201 io.pfrio_flags = flags; 202 io.pfrio_table = *tbl; 203 io.pfrio_buffer = addr; 204 io.pfrio_esize = sizeof(*addr); 205 io.pfrio_size = *size; 206 if (ioctl(dev, DIOCRGETASTATS, &io)) { 207 pfr_report_error(tbl, &io, "get astats from"); 208 return (-1); 209 } 210 *size = io.pfrio_size; 211 return (0); 212 } 213 214 int 215 pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, 216 int *nzero, int flags) 217 { 218 struct pfioc_table io; 219 220 if (size < 0 || !tbl || (size && !addr)) { 221 errno = EINVAL; 222 return (-1); 223 } 224 bzero(&io, sizeof io); 225 io.pfrio_flags = flags; 226 io.pfrio_table = *tbl; 227 io.pfrio_buffer = addr; 228 io.pfrio_esize = sizeof(*addr); 229 io.pfrio_size = size; 230 if (ioctl(dev, DIOCRCLRASTATS, &io) == -1) 231 return (-1); 232 if (nzero) 233 *nzero = io.pfrio_nzero; 234 return (0); 235 } 236 237 int 238 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 239 int *nmatch, int flags) 240 { 241 struct pfioc_table io; 242 243 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 244 errno = EINVAL; 245 return (-1); 246 } 247 bzero(&io, sizeof io); 248 io.pfrio_flags = flags; 249 io.pfrio_table = *tbl; 250 io.pfrio_buffer = addr; 251 io.pfrio_esize = sizeof(*addr); 252 io.pfrio_size = size; 253 if (ioctl(dev, DIOCRTSTADDRS, &io)) { 254 pfr_report_error(tbl, &io, "test addresses in"); 255 return (-1); 256 } 257 if (nmatch) 258 *nmatch = io.pfrio_nmatch; 259 return (0); 260 } 261 262 int 263 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, 264 int *nadd, int *naddr, int ticket, int flags) 265 { 266 struct pfioc_table io; 267 268 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 269 errno = EINVAL; 270 return (-1); 271 } 272 bzero(&io, sizeof io); 273 io.pfrio_flags = flags; 274 io.pfrio_table = *tbl; 275 io.pfrio_buffer = addr; 276 io.pfrio_esize = sizeof(*addr); 277 io.pfrio_size = size; 278 io.pfrio_ticket = ticket; 279 if (ioctl(dev, DIOCRINADEFINE, &io)) { 280 pfr_report_error(tbl, &io, "define inactive set table"); 281 return (-1); 282 } 283 if (nadd != NULL) 284 *nadd = io.pfrio_nadd; 285 if (naddr != NULL) 286 *naddr = io.pfrio_naddr; 287 return (0); 288 } 289 290 /* interface management code */ 291 292 int 293 pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size) 294 { 295 struct pfioc_iface io; 296 297 if (size == NULL || *size < 0 || (*size && buf == NULL)) { 298 errno = EINVAL; 299 return (-1); 300 } 301 bzero(&io, sizeof io); 302 if (filter != NULL) 303 if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >= 304 sizeof(io.pfiio_name)) { 305 errno = EINVAL; 306 return (-1); 307 } 308 io.pfiio_buffer = buf; 309 io.pfiio_esize = sizeof(*buf); 310 io.pfiio_size = *size; 311 if (ioctl(dev, DIOCIGETIFACES, &io)) 312 return (-1); 313 *size = io.pfiio_size; 314 return (0); 315 } 316 317 /* buffer management code */ 318 319 const size_t buf_esize[PFRB_MAX] = { 0, 320 sizeof(struct pfr_table), sizeof(struct pfr_tstats), 321 sizeof(struct pfr_addr), sizeof(struct pfr_astats), 322 sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e) 323 }; 324 325 /* 326 * add one element to the buffer 327 */ 328 int 329 pfr_buf_add(struct pfr_buffer *b, const void *e) 330 { 331 size_t bs; 332 333 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX || 334 e == NULL) { 335 errno = EINVAL; 336 return (-1); 337 } 338 bs = buf_esize[b->pfrb_type]; 339 if (b->pfrb_size == b->pfrb_msize) 340 if (pfr_buf_grow(b, 0)) 341 return (-1); 342 memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs); 343 b->pfrb_size++; 344 return (0); 345 } 346 347 /* 348 * return next element of the buffer (or first one if prev is NULL) 349 * see PFRB_FOREACH macro 350 */ 351 void * 352 pfr_buf_next(struct pfr_buffer *b, const void *prev) 353 { 354 size_t bs; 355 356 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) 357 return (NULL); 358 if (b->pfrb_size == 0) 359 return (NULL); 360 if (prev == NULL) 361 return (b->pfrb_caddr); 362 bs = buf_esize[b->pfrb_type]; 363 if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1) 364 return (NULL); 365 return (((caddr_t)prev) + bs); 366 } 367 368 /* 369 * minsize: 370 * 0: make the buffer somewhat bigger 371 * n: make room for "n" entries in the buffer 372 */ 373 int 374 pfr_buf_grow(struct pfr_buffer *b, int minsize) 375 { 376 caddr_t p; 377 size_t bs; 378 379 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) { 380 errno = EINVAL; 381 return (-1); 382 } 383 if (minsize != 0 && minsize <= b->pfrb_msize) 384 return (0); 385 bs = buf_esize[b->pfrb_type]; 386 if (!b->pfrb_msize) { 387 if (minsize < 64) 388 minsize = 64; 389 } 390 if (minsize == 0) 391 minsize = b->pfrb_msize * 2; 392 p = reallocarray(b->pfrb_caddr, minsize, bs); 393 if (p == NULL) 394 return (-1); 395 bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs); 396 b->pfrb_caddr = p; 397 b->pfrb_msize = minsize; 398 return (0); 399 } 400 401 /* 402 * reset buffer and free memory. 403 */ 404 void 405 pfr_buf_clear(struct pfr_buffer *b) 406 { 407 if (b == NULL) 408 return; 409 free(b->pfrb_caddr); 410 b->pfrb_caddr = NULL; 411 b->pfrb_size = b->pfrb_msize = 0; 412 } 413 414 int 415 pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork, 416 int (*append_addr)(struct pfr_buffer *, char *, int)) 417 { 418 FILE *fp; 419 char buf[BUF_SIZE]; 420 int rv; 421 422 if (file == NULL) 423 return (0); 424 if (!strcmp(file, "-")) 425 fp = stdin; 426 else { 427 fp = pfctl_fopen(file, "r"); 428 if (fp == NULL) 429 return (-1); 430 } 431 while ((rv = pfr_next_token(buf, fp)) == 1) 432 if (append_addr(b, buf, nonetwork)) { 433 rv = -1; 434 break; 435 } 436 if (fp != stdin) 437 fclose(fp); 438 return (rv); 439 } 440 441 int 442 pfr_next_token(char buf[BUF_SIZE], FILE *fp) 443 { 444 static char next_ch = ' '; 445 int i = 0; 446 447 for (;;) { 448 /* skip spaces */ 449 while (isspace(next_ch) && !feof(fp)) 450 next_ch = fgetc(fp); 451 /* remove from '#' or ';' until end of line */ 452 if (next_ch == '#' || next_ch == ';') 453 while (!feof(fp)) { 454 next_ch = fgetc(fp); 455 if (next_ch == '\n') 456 break; 457 } 458 else 459 break; 460 } 461 if (feof(fp)) { 462 next_ch = ' '; 463 return (0); 464 } 465 do { 466 if (i < BUF_SIZE) 467 buf[i++] = next_ch; 468 next_ch = fgetc(fp); 469 } while (!feof(fp) && !isspace(next_ch)); 470 if (i >= BUF_SIZE) { 471 errno = EINVAL; 472 return (-1); 473 } 474 buf[i] = '\0'; 475 return (1); 476 } 477 478 char * 479 pfr_strerror(int errnum) 480 { 481 switch (errnum) { 482 case ESRCH: 483 return "Table does not exist"; 484 case ENOENT: 485 return "Anchor or Ruleset does not exist"; 486 default: 487 return strerror(errnum); 488 } 489 } 490