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