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