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_tstats(struct pfr_table * tbl,int size,int * nzero,int flags)290 pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
291 {
292 struct pfioc_table io;
293
294 if (size < 0 || (size && !tbl)) {
295 errno = EINVAL;
296 return (-1);
297 }
298 bzero(&io, sizeof io);
299 io.pfrio_flags = flags;
300 io.pfrio_buffer = tbl;
301 io.pfrio_esize = sizeof(*tbl);
302 io.pfrio_size = size;
303 if (ioctl(dev, DIOCRCLRTSTATS, &io)) {
304 pfr_report_error(tbl, &io, "clear tstats from");
305 return (-1);
306 }
307 if (nzero)
308 *nzero = io.pfrio_nzero;
309 return (0);
310 }
311
312 int
pfr_tst_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nmatch,int flags)313 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
314 int *nmatch, int flags)
315 {
316 struct pfioc_table io;
317
318 if (tbl == NULL || size < 0 || (size && addr == NULL)) {
319 errno = EINVAL;
320 return (-1);
321 }
322 bzero(&io, sizeof io);
323 io.pfrio_flags = flags;
324 io.pfrio_table = *tbl;
325 io.pfrio_buffer = addr;
326 io.pfrio_esize = sizeof(*addr);
327 io.pfrio_size = size;
328 if (ioctl(dev, DIOCRTSTADDRS, &io)) {
329 pfr_report_error(tbl, &io, "test addresses in");
330 return (-1);
331 }
332 if (nmatch)
333 *nmatch = io.pfrio_nmatch;
334 return (0);
335 }
336
337 int
pfr_ina_define(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int * naddr,int ticket,int flags)338 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
339 int *nadd, int *naddr, int ticket, int flags)
340 {
341 struct pfioc_table io;
342
343 if (tbl == NULL || size < 0 || (size && addr == NULL)) {
344 errno = EINVAL;
345 return (-1);
346 }
347 bzero(&io, sizeof io);
348 io.pfrio_flags = flags;
349 io.pfrio_table = *tbl;
350 io.pfrio_buffer = addr;
351 io.pfrio_esize = sizeof(*addr);
352 io.pfrio_size = size;
353 io.pfrio_ticket = ticket;
354 if (ioctl(dev, DIOCRINADEFINE, &io)) {
355 pfr_report_error(tbl, &io, "define inactive set table");
356 return (-1);
357 }
358 if (nadd != NULL)
359 *nadd = io.pfrio_nadd;
360 if (naddr != NULL)
361 *naddr = io.pfrio_naddr;
362 return (0);
363 }
364
365 /* interface management code */
366
367 int
pfi_get_ifaces(const char * filter,struct pfi_kif * buf,int * size)368 pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size)
369 {
370 struct pfioc_iface io;
371
372 if (size == NULL || *size < 0 || (*size && buf == NULL)) {
373 errno = EINVAL;
374 return (-1);
375 }
376 bzero(&io, sizeof io);
377 if (filter != NULL)
378 if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >=
379 sizeof(io.pfiio_name)) {
380 errno = EINVAL;
381 return (-1);
382 }
383 io.pfiio_buffer = buf;
384 io.pfiio_esize = sizeof(*buf);
385 io.pfiio_size = *size;
386 if (ioctl(dev, DIOCIGETIFACES, &io))
387 return (-1);
388 *size = io.pfiio_size;
389 return (0);
390 }
391
392 /* buffer management code */
393
394 const size_t buf_esize[PFRB_MAX] = { 0,
395 sizeof(struct pfr_table), sizeof(struct pfr_tstats),
396 sizeof(struct pfr_addr), sizeof(struct pfr_astats),
397 sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e)
398 };
399
400 /*
401 * add one element to the buffer
402 */
403 int
pfr_buf_add(struct pfr_buffer * b,const void * e)404 pfr_buf_add(struct pfr_buffer *b, const void *e)
405 {
406 size_t bs;
407
408 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX ||
409 e == NULL) {
410 errno = EINVAL;
411 return (-1);
412 }
413 bs = buf_esize[b->pfrb_type];
414 if (b->pfrb_size == b->pfrb_msize)
415 if (pfr_buf_grow(b, 0))
416 return (-1);
417 memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs);
418 b->pfrb_size++;
419 return (0);
420 }
421
422 /*
423 * return next element of the buffer (or first one if prev is NULL)
424 * see PFRB_FOREACH macro
425 */
426 void *
pfr_buf_next(struct pfr_buffer * b,const void * prev)427 pfr_buf_next(struct pfr_buffer *b, const void *prev)
428 {
429 size_t bs;
430
431 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX)
432 return (NULL);
433 if (b->pfrb_size == 0)
434 return (NULL);
435 if (prev == NULL)
436 return (b->pfrb_caddr);
437 bs = buf_esize[b->pfrb_type];
438 if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1)
439 return (NULL);
440 return (((caddr_t)prev) + bs);
441 }
442
443 /*
444 * minsize:
445 * 0: make the buffer somewhat bigger
446 * n: make room for "n" entries in the buffer
447 */
448 int
pfr_buf_grow(struct pfr_buffer * b,int minsize)449 pfr_buf_grow(struct pfr_buffer *b, int minsize)
450 {
451 caddr_t p;
452 size_t bs;
453
454 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) {
455 errno = EINVAL;
456 return (-1);
457 }
458 if (minsize != 0 && minsize <= b->pfrb_msize)
459 return (0);
460 bs = buf_esize[b->pfrb_type];
461 if (!b->pfrb_msize) {
462 if (minsize < 64)
463 minsize = 64;
464 b->pfrb_caddr = calloc(bs, minsize);
465 if (b->pfrb_caddr == NULL)
466 return (-1);
467 b->pfrb_msize = minsize;
468 } else {
469 if (minsize == 0)
470 minsize = b->pfrb_msize * 2;
471 if (minsize < 0 || minsize >= SIZE_T_MAX / bs) {
472 /* msize overflow */
473 errno = ENOMEM;
474 return (-1);
475 }
476 p = realloc(b->pfrb_caddr, minsize * bs);
477 if (p == NULL)
478 return (-1);
479 bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs);
480 b->pfrb_caddr = p;
481 b->pfrb_msize = minsize;
482 }
483 return (0);
484 }
485
486 /*
487 * reset buffer and free memory.
488 */
489 void
pfr_buf_clear(struct pfr_buffer * b)490 pfr_buf_clear(struct pfr_buffer *b)
491 {
492 if (b == NULL)
493 return;
494 if (b->pfrb_caddr != NULL)
495 free(b->pfrb_caddr);
496 b->pfrb_caddr = NULL;
497 b->pfrb_size = b->pfrb_msize = 0;
498 }
499
500 int
pfr_buf_load(struct pfr_buffer * b,char * file,int nonetwork,int (* append_addr)(struct pfr_buffer *,char *,int))501 pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork,
502 int (*append_addr)(struct pfr_buffer *, char *, int))
503 {
504 FILE *fp;
505 char buf[BUF_SIZE];
506 int rv;
507
508 if (file == NULL)
509 return (0);
510 if (!strcmp(file, "-"))
511 fp = stdin;
512 else {
513 fp = pfctl_fopen(file, "r");
514 if (fp == NULL)
515 return (-1);
516 }
517 while ((rv = pfr_next_token(buf, fp)) == 1)
518 if (append_addr(b, buf, nonetwork)) {
519 rv = -1;
520 break;
521 }
522 if (fp != stdin)
523 fclose(fp);
524 return (rv);
525 }
526
527 int
pfr_next_token(char buf[BUF_SIZE],FILE * fp)528 pfr_next_token(char buf[BUF_SIZE], FILE *fp)
529 {
530 static char next_ch = ' ';
531 int i = 0;
532
533 for (;;) {
534 /* skip spaces */
535 while (isspace(next_ch) && !feof(fp))
536 next_ch = fgetc(fp);
537 /* remove from '#' until end of line */
538 if (next_ch == '#')
539 while (!feof(fp)) {
540 next_ch = fgetc(fp);
541 if (next_ch == '\n')
542 break;
543 }
544 else
545 break;
546 }
547 if (feof(fp)) {
548 next_ch = ' ';
549 return (0);
550 }
551 do {
552 if (i < BUF_SIZE)
553 buf[i++] = next_ch;
554 next_ch = fgetc(fp);
555 } while (!feof(fp) && !isspace(next_ch));
556 if (i >= BUF_SIZE) {
557 errno = EINVAL;
558 return (-1);
559 }
560 buf[i] = '\0';
561 return (1);
562 }
563
564 char *
pfr_strerror(int errnum)565 pfr_strerror(int errnum)
566 {
567 switch (errnum) {
568 case ESRCH:
569 return "Table does not exist";
570 case ENOENT:
571 return "Anchor or Ruleset does not exist";
572 default:
573 return strerror(errnum);
574 }
575 }
576