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