1 /* $OpenBSD: pf.c,v 1.1.1.1 2022/09/01 14:20:33 martijn Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Joel Knight <joel@openbsd.org> 5 * Copyright (c) 2002 Cedric Berger 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * - Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * - Redistributions in binary form must reproduce the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer in the documentation and/or other materials provided 17 * with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 * 32 */ 33 34 #include <sys/types.h> 35 #include <sys/socket.h> 36 #include <sys/ioctl.h> 37 38 #include <netinet/in.h> 39 #include <arpa/inet.h> 40 #include <net/if.h> 41 #include <net/pfvar.h> 42 43 #include <err.h> 44 #include <errno.h> 45 #include <fcntl.h> 46 #include <stdint.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <unistd.h> 51 #include <event.h> 52 53 #include "snmpd.h" 54 55 int devpf = 0; 56 57 size_t buf_esize[PFRB_MAX] = { 0, 58 sizeof(struct pfr_table), sizeof(struct pfr_tstats), 59 sizeof(struct pfr_addr), sizeof(struct pfr_astats), 60 sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e) 61 }; 62 63 void 64 pf_init(void) 65 { 66 if ((devpf = open("/dev/pf", O_RDONLY)) == -1) 67 fatal("pf_init"); 68 } 69 70 int 71 pf_get_stats(struct pf_status *s) 72 { 73 extern int devpf; 74 75 memset(s, 0, sizeof(*s)); 76 if (ioctl(devpf, DIOCGETSTATUS, s) == -1) { 77 log_warn("DIOCGETSTATUS"); 78 return (-1); 79 } 80 81 return (0); 82 } 83 84 int 85 pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, 86 int flags) 87 { 88 struct pfioc_table io; 89 extern int devpf; 90 91 if (tbl == NULL || size == NULL || *size < 0 || 92 (*size && addr == NULL)) 93 return (-1); 94 95 bzero(&io, sizeof io); 96 io.pfrio_flags = flags; 97 io.pfrio_table = *tbl; 98 io.pfrio_buffer = addr; 99 io.pfrio_esize = sizeof(*addr); 100 io.pfrio_size = *size; 101 if (ioctl(devpf, DIOCRGETASTATS, &io) == -1) 102 return (-1); 103 *size = io.pfrio_size; 104 return (0); 105 } 106 107 int 108 pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, 109 int flags) 110 { 111 struct pfioc_table io; 112 extern int devpf; 113 114 if (size == NULL || *size < 0 || (*size && tbl == NULL)) 115 return (-1); 116 bzero(&io, sizeof io); 117 io.pfrio_flags = flags; 118 if (filter != NULL) 119 io.pfrio_table = *filter; 120 io.pfrio_buffer = tbl; 121 io.pfrio_esize = sizeof(*tbl); 122 io.pfrio_size = *size; 123 if (ioctl(devpf, DIOCRGETTSTATS, &io) == -1) 124 return (-1); 125 *size = io.pfrio_size; 126 return (0); 127 } 128 129 int 130 pfr_buf_grow(struct pfr_buffer *b, int minsize) 131 { 132 caddr_t p; 133 size_t bs; 134 135 if (minsize != 0 && minsize <= b->pfrb_msize) 136 return (0); 137 bs = buf_esize[b->pfrb_type]; 138 if (!b->pfrb_msize) { 139 if (minsize < 64) 140 minsize = 64; 141 b->pfrb_caddr = calloc(bs, minsize); 142 if (b->pfrb_caddr == NULL) 143 return (-1); 144 b->pfrb_msize = minsize; 145 } else { 146 if (minsize == 0) 147 minsize = b->pfrb_msize * 2; 148 if (minsize < 0 || (size_t)minsize >= SIZE_MAX / bs) { 149 /* msize overflow */ 150 return (-1); 151 } 152 p = reallocarray(b->pfrb_caddr, minsize, bs); 153 if (p == NULL) 154 return (-1); 155 bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs); 156 b->pfrb_caddr = p; 157 b->pfrb_msize = minsize; 158 } 159 return (0); 160 } 161 162 const void * 163 pfr_buf_next(struct pfr_buffer *b, const void *prev) 164 { 165 size_t bs; 166 167 if (b == NULL) 168 return (NULL); 169 if (b->pfrb_size == 0) 170 return (NULL); 171 if (prev == NULL) 172 return (b->pfrb_caddr); 173 bs = buf_esize[b->pfrb_type]; 174 if ((((const char *)prev)-((char *)b->pfrb_caddr)) / bs >= 175 (size_t)b->pfrb_size-1) 176 return (NULL); 177 178 return (((const char *)prev) + bs); 179 } 180 181 int 182 pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size) 183 { 184 struct pfioc_iface io; 185 extern int devpf; 186 187 if (size == NULL || *size < 0 || (*size && buf == NULL)) { 188 errno = EINVAL; 189 return (-1); 190 } 191 bzero(&io, sizeof io); 192 if (filter != NULL) 193 if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >= 194 sizeof(io.pfiio_name)) { 195 errno = EINVAL; 196 return (-1); 197 } 198 io.pfiio_buffer = buf; 199 io.pfiio_esize = sizeof(*buf); 200 io.pfiio_size = *size; 201 if (ioctl(devpf, DIOCIGETIFACES, &io) == -1) 202 return (-1); 203 *size = io.pfiio_size; 204 return (0); 205 } 206 207 int 208 pfi_get(struct pfr_buffer *b, const char *filter) 209 { 210 bzero(b, sizeof(struct pfr_buffer)); 211 b->pfrb_type = PFRB_IFACES; 212 for (;;) { 213 pfr_buf_grow(b, b->pfrb_size); 214 b->pfrb_size = b->pfrb_msize; 215 if (pfi_get_ifaces(filter, b->pfrb_caddr, &(b->pfrb_size))) 216 return (1); 217 if (b->pfrb_size <= b->pfrb_msize) 218 break; 219 } 220 221 return (0); 222 } 223 224 int 225 pfi_count(void) 226 { 227 struct pfr_buffer b; 228 const struct pfi_kif *p; 229 int c = 0; 230 231 if (pfi_get(&b, NULL)) { 232 free(b.pfrb_caddr); 233 return (-1); 234 } 235 236 PFRB_FOREACH(p, &b) 237 c++; 238 239 free(b.pfrb_caddr); 240 return (c); 241 } 242 243 int 244 pfi_get_if(struct pfi_kif *rp, int idx) 245 { 246 struct pfr_buffer b; 247 const struct pfi_kif *p; 248 int i = 1; 249 250 if (pfi_get(&b, NULL)) { 251 free(b.pfrb_caddr); 252 return (-1); 253 } 254 255 PFRB_FOREACH(p, &b) { 256 if (i == idx) 257 break; 258 i++; 259 } 260 261 if (p == NULL) { 262 free(b.pfrb_caddr); 263 return (-1); 264 } 265 266 bcopy(p, rp, sizeof(struct pfi_kif)); 267 free(b.pfrb_caddr); 268 269 return (0); 270 } 271 272 int 273 pft_get(struct pfr_buffer *b, struct pfr_table *filter) 274 { 275 bzero(b, sizeof(struct pfr_buffer)); 276 b->pfrb_type = PFRB_TSTATS; 277 278 for (;;) { 279 pfr_buf_grow(b, b->pfrb_size); 280 b->pfrb_size = b->pfrb_msize; 281 if (pfr_get_tstats(filter, b->pfrb_caddr, &(b->pfrb_size), 0)) 282 return (1); 283 if (b->pfrb_size <= b->pfrb_msize) 284 break; 285 } 286 287 return (0); 288 } 289 290 int 291 pft_get_table(struct pfr_tstats *rts, int idx) 292 { 293 struct pfr_buffer b; 294 const struct pfr_tstats *ts; 295 int i = 1; 296 297 if (pft_get(&b, NULL)) { 298 free(b.pfrb_caddr); 299 return (-1); 300 } 301 302 PFRB_FOREACH(ts, &b) { 303 if (!(ts->pfrts_flags & PFR_TFLAG_ACTIVE)) 304 continue; 305 if (i == idx) 306 break; 307 i++; 308 } 309 310 if (ts == NULL) { 311 free(b.pfrb_caddr); 312 return (-1); 313 } 314 315 bcopy(ts, rts, sizeof(struct pfr_tstats)); 316 free(b.pfrb_caddr); 317 318 return (0); 319 } 320 321 int 322 pft_count(void) 323 { 324 struct pfr_buffer b; 325 const struct pfr_tstats *ts; 326 int c = 0; 327 328 if (pft_get(&b, NULL)) { 329 free(b.pfrb_caddr); 330 return (-1); 331 } 332 333 PFRB_FOREACH(ts, &b) { 334 if (!(ts->pfrts_flags & PFR_TFLAG_ACTIVE)) 335 continue; 336 c++; 337 } 338 339 free(b.pfrb_caddr); 340 return (c); 341 } 342 343 int 344 pfta_get(struct pfr_buffer *b, struct pfr_table *filter) 345 { 346 bzero(b, sizeof(struct pfr_buffer)); 347 b->pfrb_type = PFRB_ASTATS; 348 349 for (;;) { 350 pfr_buf_grow(b, b->pfrb_size); 351 b->pfrb_size = b->pfrb_msize; 352 if (pfr_get_astats(filter, b->pfrb_caddr, &(b->pfrb_size), 0)) { 353 return (1); 354 } 355 if (b->pfrb_size <= b->pfrb_msize) 356 break; 357 } 358 359 return (0); 360 } 361 362 int 363 pfta_get_addr(struct pfr_astats *ras, int tblidx) 364 { 365 struct pfr_buffer ba; 366 struct pfr_tstats ts; 367 struct pfr_table filter; 368 const struct pfr_astats *as; 369 370 if (pft_get_table(&ts, tblidx)) 371 return (-1); 372 373 bzero(&filter, sizeof(filter)); 374 if (strlcpy(filter.pfrt_name, ts.pfrts_name, 375 sizeof(filter.pfrt_name)) >= sizeof(filter.pfrt_name)) { 376 return (-1); 377 } 378 379 if (pfta_get(&ba, &filter) || ba.pfrb_size == 0) { 380 free(ba.pfrb_caddr); 381 return (-1); 382 } 383 384 PFRB_FOREACH(as, &ba) { 385 if (as->pfras_a.pfra_af != AF_INET) 386 continue; 387 if ((memcmp(&as->pfras_a.pfra_ip4addr, &ras->pfras_a.pfra_ip4addr, 388 sizeof(as->pfras_a.pfra_ip4addr)) == 0) 389 && (as->pfras_a.pfra_net == ras->pfras_a.pfra_net)) 390 break; 391 } 392 393 if (as == NULL) { 394 free(ba.pfrb_caddr); 395 return (-1); 396 } 397 398 bcopy(as, ras, sizeof(struct pfr_astats)); 399 free(ba.pfrb_caddr); 400 401 return (0); 402 } 403 404 int 405 pfta_get_nextaddr(struct pfr_astats *ras, int *tblidx) 406 { 407 struct pfr_buffer ba; 408 struct pfr_tstats ts; 409 struct pfr_table filter; 410 const struct pfr_astats *as; 411 int i, found = 0, cmp; 412 413 ba.pfrb_caddr = NULL; 414 415 for (i = *tblidx; !pft_get_table(&ts, i); i++) { 416 bzero(&filter, sizeof(filter)); 417 if (strlcpy(filter.pfrt_name, ts.pfrts_name, 418 sizeof(filter.pfrt_name)) >= sizeof(filter.pfrt_name)) 419 goto fail; 420 421 if (pfta_get(&ba, &filter) || ba.pfrb_size == 0) 422 goto fail; 423 424 PFRB_FOREACH(as, &ba) { 425 if (as->pfras_a.pfra_af != AF_INET) 426 continue; 427 if (found) 428 goto found; 429 cmp = memcmp(&as->pfras_a.pfra_ip4addr, 430 &ras->pfras_a.pfra_ip4addr, 431 sizeof(as->pfras_a.pfra_ip4addr)); 432 if (cmp == 0) { 433 if (as->pfras_a.pfra_net == 434 ras->pfras_a.pfra_net) 435 found = 1; 436 if (as->pfras_a.pfra_net > 437 ras->pfras_a.pfra_net) 438 goto found; 439 } else if (cmp > 0) 440 goto found; 441 } 442 443 free(ba.pfrb_caddr); 444 ba.pfrb_caddr = NULL; 445 } 446 447 448 fail: 449 free(ba.pfrb_caddr); 450 451 return (-1); 452 453 found: 454 bcopy(as, ras, sizeof(struct pfr_astats)); 455 *tblidx = i; 456 457 free(ba.pfrb_caddr); 458 459 return (0); 460 } 461 462 int 463 pfta_get_first(struct pfr_astats *ras) 464 { 465 struct pfr_buffer ba; 466 struct pfr_tstats ts; 467 struct pfr_table filter; 468 const struct pfr_astats *as; 469 470 if (pft_get_table(&ts, 1)) 471 return (-1); 472 473 bzero(&filter, sizeof(filter)); 474 if (strlcpy(filter.pfrt_name, ts.pfrts_name, 475 sizeof(filter.pfrt_name)) >= sizeof(filter.pfrt_name)) { 476 return (-1); 477 } 478 479 if (pfta_get(&ba, &filter) || ba.pfrb_size == 0) { 480 free(ba.pfrb_caddr); 481 return (-1); 482 } 483 484 /* take the first AF_INET addr */ 485 PFRB_FOREACH(as, &ba) { 486 if (as->pfras_a.pfra_af != AF_INET) 487 continue; 488 break; 489 } 490 491 if (as == NULL) { 492 free(ba.pfrb_caddr); 493 return (-1); 494 } 495 496 bcopy(as, ras, sizeof(struct pfr_astats)); 497 free(ba.pfrb_caddr); 498 499 return (0); 500 } 501 502