1 /* $OpenBSD: pfctl_radix.c,v 1.27 2005/05/21 21:03:58 henning Exp $ */
4 * SPDX-License-Identifier: BSD-2-Clause
6 * Copyright (c) 2002 Cedric Berger
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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.
35 #include <sys/cdefs.h>
36 #include <sys/types.h>
37 #include <sys/ioctl.h>
38 #include <sys/socket.h>
41 #include <net/pfvar.h>
57 static int pfr_next_token(char buf[BUF_SIZE], FILE *);
60 pfr_report_error(struct pfr_table *tbl, struct pfioc_table *io,
63 unsigned long maxcount;
67 if (sysctlbyname("net.pf.request_maxcount", &maxcount, &s, NULL,
71 if (io->pfrio_size > maxcount || io->pfrio_size2 > maxcount)
72 fprintf(stderr, "cannot %s %s: too many elements.\n"
73 "Consider increasing net.pf.request_maxcount.",
78 pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
80 struct pfioc_table io;
82 bzero(&io, sizeof io);
83 io.pfrio_flags = flags;
85 io.pfrio_table = *filter;
86 if (ioctl(dev, DIOCRCLRTABLES, &io))
89 *ndel = io.pfrio_ndel;
94 pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
96 struct pfioc_table io;
98 if (size < 0 || (size && tbl == NULL)) {
102 bzero(&io, sizeof io);
103 io.pfrio_flags = flags;
104 io.pfrio_buffer = tbl;
105 io.pfrio_esize = sizeof(*tbl);
106 io.pfrio_size = size;
107 if (ioctl(dev, DIOCRADDTABLES, &io)) {
108 pfr_report_error(tbl, &io, "add table");
112 *nadd = io.pfrio_nadd;
117 pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
119 struct pfioc_table io;
121 if (size < 0 || (size && tbl == NULL)) {
125 bzero(&io, sizeof io);
126 io.pfrio_flags = flags;
127 io.pfrio_buffer = tbl;
128 io.pfrio_esize = sizeof(*tbl);
129 io.pfrio_size = size;
130 if (ioctl(dev, DIOCRDELTABLES, &io)) {
131 pfr_report_error(tbl, &io, "delete table");
135 *ndel = io.pfrio_ndel;
140 pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
143 struct pfioc_table io;
145 if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
149 bzero(&io, sizeof io);
150 io.pfrio_flags = flags;
152 io.pfrio_table = *filter;
153 io.pfrio_buffer = tbl;
154 io.pfrio_esize = sizeof(*tbl);
155 io.pfrio_size = *size;
156 if (ioctl(dev, DIOCRGETTABLES, &io)) {
157 pfr_report_error(tbl, &io, "get table");
160 *size = io.pfrio_size;
165 pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
168 struct pfioc_table io;
170 if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
174 bzero(&io, sizeof io);
175 io.pfrio_flags = flags;
177 io.pfrio_table = *filter;
178 io.pfrio_buffer = tbl;
179 io.pfrio_esize = sizeof(*tbl);
180 io.pfrio_size = *size;
181 if (ioctl(dev, DIOCRGETTSTATS, &io)) {
182 pfr_report_error(filter, &io, "get tstats for");
185 *size = io.pfrio_size;
190 pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
192 struct pfioc_table io;
198 bzero(&io, sizeof io);
199 io.pfrio_flags = flags;
200 io.pfrio_table = *tbl;
201 if (ioctl(dev, DIOCRCLRADDRS, &io))
204 *ndel = io.pfrio_ndel;
209 pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
210 int *nadd, int flags)
214 ret = pfctl_table_add_addrs(dev, tbl, addr, size, nadd, flags);
223 pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
224 int *ndel, int flags)
228 ret = pfctl_table_del_addrs(dev, tbl, addr, size, ndel, flags);
237 pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
238 int *size2, int *nadd, int *ndel, int *nchange, int flags)
242 ret = pfctl_table_set_addrs(dev, tbl, addr, size, size2, nadd, ndel,
252 pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
257 ret = pfctl_table_get_addrs(dev, tbl, addr, size, flags);
266 pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
269 struct pfioc_table io;
271 if (tbl == NULL || size == NULL || *size < 0 ||
272 (*size && addr == NULL)) {
276 bzero(&io, sizeof io);
277 io.pfrio_flags = flags;
278 io.pfrio_table = *tbl;
279 io.pfrio_buffer = addr;
280 io.pfrio_esize = sizeof(*addr);
281 io.pfrio_size = *size;
282 if (ioctl(dev, DIOCRGETASTATS, &io)) {
283 pfr_report_error(tbl, &io, "get astats from");
286 *size = io.pfrio_size;
291 pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
293 struct pfioc_table io;
295 if (size < 0 || (size && !tbl)) {
299 bzero(&io, sizeof io);
300 io.pfrio_flags = flags;
301 io.pfrio_buffer = tbl;
302 io.pfrio_esize = sizeof(*tbl);
303 io.pfrio_size = size;
304 if (ioctl(dev, DIOCRCLRTSTATS, &io)) {
305 pfr_report_error(tbl, &io, "clear tstats from");
309 *nzero = io.pfrio_nzero;
314 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
315 int *nmatch, int flags)
317 struct pfioc_table io;
319 if (tbl == NULL || size < 0 || (size && addr == NULL)) {
323 bzero(&io, sizeof io);
324 io.pfrio_flags = flags;
325 io.pfrio_table = *tbl;
326 io.pfrio_buffer = addr;
327 io.pfrio_esize = sizeof(*addr);
328 io.pfrio_size = size;
329 if (ioctl(dev, DIOCRTSTADDRS, &io)) {
330 pfr_report_error(tbl, &io, "test addresses in");
334 *nmatch = io.pfrio_nmatch;
339 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
340 int *nadd, int *naddr, int ticket, int flags)
342 struct pfioc_table io;
344 if (tbl == NULL || size < 0 || (size && addr == NULL)) {
348 bzero(&io, sizeof io);
349 io.pfrio_flags = flags;
350 io.pfrio_table = *tbl;
351 io.pfrio_buffer = addr;
352 io.pfrio_esize = sizeof(*addr);
353 io.pfrio_size = size;
354 io.pfrio_ticket = ticket;
355 if (ioctl(dev, DIOCRINADEFINE, &io)) {
356 pfr_report_error(tbl, &io, "define inactive set table");
360 *nadd = io.pfrio_nadd;
362 *naddr = io.pfrio_naddr;
366 /* interface management code */
369 pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size)
371 struct pfioc_iface io;
373 if (size == NULL || *size < 0 || (*size && buf == NULL)) {
377 bzero(&io, sizeof io);
379 if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >=
380 sizeof(io.pfiio_name)) {
384 io.pfiio_buffer = buf;
385 io.pfiio_esize = sizeof(*buf);
386 io.pfiio_size = *size;
387 if (ioctl(dev, DIOCIGETIFACES, &io))
389 *size = io.pfiio_size;
393 /* buffer management code */
395 const size_t buf_esize[PFRB_MAX] = { 0,
396 sizeof(struct pfr_table), sizeof(struct pfr_tstats),
397 sizeof(struct pfr_addr), sizeof(struct pfr_astats),
398 sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e)
402 * add one element to the buffer
405 pfr_buf_add(struct pfr_buffer *b, const void *e)
409 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX ||
414 bs = buf_esize[b->pfrb_type];
415 if (b->pfrb_size == b->pfrb_msize)
416 if (pfr_buf_grow(b, 0))
418 memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs);
424 * return next element of the buffer (or first one if prev is NULL)
425 * see PFRB_FOREACH macro
428 pfr_buf_next(struct pfr_buffer *b, const void *prev)
432 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX)
434 if (b->pfrb_size == 0)
437 return (b->pfrb_caddr);
438 bs = buf_esize[b->pfrb_type];
439 if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1)
441 return (((caddr_t)prev) + bs);
446 * 0: make the buffer somewhat bigger
447 * n: make room for "n" entries in the buffer
450 pfr_buf_grow(struct pfr_buffer *b, int minsize)
455 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) {
459 if (minsize != 0 && minsize <= b->pfrb_msize)
461 bs = buf_esize[b->pfrb_type];
462 if (!b->pfrb_msize) {
465 b->pfrb_caddr = calloc(bs, minsize);
466 if (b->pfrb_caddr == NULL)
468 b->pfrb_msize = minsize;
471 minsize = b->pfrb_msize * 2;
472 if (minsize < 0 || minsize >= SIZE_T_MAX / bs) {
477 p = realloc(b->pfrb_caddr, minsize * bs);
480 bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs);
482 b->pfrb_msize = minsize;
488 * reset buffer and free memory.
491 pfr_buf_clear(struct pfr_buffer *b)
495 if (b->pfrb_caddr != NULL)
497 b->pfrb_caddr = NULL;
498 b->pfrb_size = b->pfrb_msize = 0;
502 pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork,
503 int (*append_addr)(struct pfr_buffer *, char *, int))
511 if (!strcmp(file, "-"))
514 fp = pfctl_fopen(file, "r");
518 while ((rv = pfr_next_token(buf, fp)) == 1)
519 if (append_addr(b, buf, nonetwork)) {
529 pfr_next_token(char buf[BUF_SIZE], FILE *fp)
531 static char next_ch = ' ';
536 while (isspace(next_ch) && !feof(fp))
538 /* remove from '#' until end of line */
556 } while (!feof(fp) && !isspace(next_ch));
566 pfr_strerror(int errnum)
570 return "Table does not exist";
572 return "Anchor or Ruleset does not exist";
574 return strerror(errnum);