1 /* $OpenBSD: pfctl_radix.c,v 1.38 2023/09/05 15:37:07 robert Exp $ */
2
3 /*
4 * Copyright (c) 2002 Cedric Berger
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 */
32
33 #include <sys/types.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
36
37 #include <netinet/in.h>
38 #include <net/if.h>
39 #include <net/pfvar.h>
40
41 #include <errno.h>
42 #include <string.h>
43 #include <ctype.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <limits.h>
47 #include <err.h>
48
49 #include "pfctl.h"
50 #include "pfctl_parser.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
59 int
pfr_clr_tables(struct pfr_table * filter,int * ndel,int flags)60 pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
61 {
62 struct pfioc_table io;
63
64 bzero(&io, sizeof io);
65 io.pfrio_flags = flags;
66 if (filter != NULL)
67 io.pfrio_table = *filter;
68 if (ioctl(dev, DIOCRCLRTABLES, &io) == -1)
69 return (-1);
70 if (ndel != NULL)
71 *ndel = io.pfrio_ndel;
72 return (0);
73 }
74
75 int
pfr_add_tables(struct pfr_table * tbl,int size,int * nadd,int flags)76 pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
77 {
78 struct pfioc_table io;
79
80 if (size < 0 || (size && tbl == NULL)) {
81 errno = EINVAL;
82 return (-1);
83 }
84 bzero(&io, sizeof io);
85 io.pfrio_flags = flags;
86 io.pfrio_buffer = tbl;
87 io.pfrio_esize = sizeof(*tbl);
88 io.pfrio_size = size;
89 if (ioctl(dev, DIOCRADDTABLES, &io) == -1)
90 return (-1);
91 if (nadd != NULL)
92 *nadd = io.pfrio_nadd;
93 return (0);
94 }
95
96 int
pfr_del_tables(struct pfr_table * tbl,int size,int * ndel,int flags)97 pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
98 {
99 struct pfioc_table io;
100
101 if (size < 0 || (size && tbl == NULL)) {
102 errno = EINVAL;
103 return (-1);
104 }
105 bzero(&io, sizeof io);
106 io.pfrio_flags = flags;
107 io.pfrio_buffer = tbl;
108 io.pfrio_esize = sizeof(*tbl);
109 io.pfrio_size = size;
110 if (ioctl(dev, DIOCRDELTABLES, &io) == -1)
111 return (-1);
112 if (ndel != NULL)
113 *ndel = io.pfrio_ndel;
114 return (0);
115 }
116
117 int
pfr_get_tables(struct pfr_table * filter,struct pfr_table * tbl,int * size,int flags)118 pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
119 int flags)
120 {
121 struct pfioc_table io;
122
123 if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
124 errno = EINVAL;
125 return (-1);
126 }
127 bzero(&io, sizeof io);
128 io.pfrio_flags = flags;
129 if (filter != NULL)
130 io.pfrio_table = *filter;
131 io.pfrio_buffer = tbl;
132 io.pfrio_esize = sizeof(*tbl);
133 io.pfrio_size = *size;
134 if (ioctl(dev, DIOCRGETTABLES, &io) == -1)
135 return (-1);
136 *size = io.pfrio_size;
137 return (0);
138 }
139
140 int
pfr_get_tstats(struct pfr_table * filter,struct pfr_tstats * tbl,int * size,int flags)141 pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
142 int flags)
143 {
144 struct pfioc_table io;
145
146 if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
147 errno = EINVAL;
148 return (-1);
149 }
150 bzero(&io, sizeof io);
151 io.pfrio_flags = flags;
152 if (filter != NULL)
153 io.pfrio_table = *filter;
154 io.pfrio_buffer = tbl;
155 io.pfrio_esize = sizeof(*tbl);
156 io.pfrio_size = *size;
157 if (ioctl(dev, DIOCRGETTSTATS, &io) == -1)
158 return (-1);
159 *size = io.pfrio_size;
160 return (0);
161 }
162
163 int
pfr_clr_addrs(struct pfr_table * tbl,int * ndel,int flags)164 pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
165 {
166 struct pfioc_table io;
167
168 if (tbl == NULL) {
169 errno = EINVAL;
170 return (-1);
171 }
172 bzero(&io, sizeof io);
173 io.pfrio_flags = flags;
174 io.pfrio_table = *tbl;
175 if (ioctl(dev, DIOCRCLRADDRS, &io) == -1)
176 return (-1);
177 if (ndel != NULL)
178 *ndel = io.pfrio_ndel;
179 return (0);
180 }
181
182 int
pfr_add_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int flags)183 pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
184 int *nadd, int flags)
185 {
186 struct pfioc_table io;
187
188 if (tbl == NULL || size < 0 || (size && addr == NULL)) {
189 errno = EINVAL;
190 return (-1);
191 }
192 bzero(&io, sizeof io);
193 io.pfrio_flags = flags;
194 io.pfrio_table = *tbl;
195 io.pfrio_buffer = addr;
196 io.pfrio_esize = sizeof(*addr);
197 io.pfrio_size = size;
198 if (ioctl(dev, DIOCRADDADDRS, &io) == -1)
199 return (-1);
200 if (nadd != NULL)
201 *nadd = io.pfrio_nadd;
202 return (0);
203 }
204
205 int
pfr_del_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * ndel,int flags)206 pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
207 int *ndel, int flags)
208 {
209 struct pfioc_table io;
210
211 if (tbl == NULL || size < 0 || (size && addr == NULL)) {
212 errno = EINVAL;
213 return (-1);
214 }
215 bzero(&io, sizeof io);
216 io.pfrio_flags = flags;
217 io.pfrio_table = *tbl;
218 io.pfrio_buffer = addr;
219 io.pfrio_esize = sizeof(*addr);
220 io.pfrio_size = size;
221 if (ioctl(dev, DIOCRDELADDRS, &io) == -1)
222 return (-1);
223 if (ndel != NULL)
224 *ndel = io.pfrio_ndel;
225 return (0);
226 }
227
228 int
pfr_set_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * size2,int * nadd,int * ndel,int * nchange,int flags)229 pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
230 int *size2, int *nadd, int *ndel, int *nchange, int flags)
231 {
232 struct pfioc_table io;
233
234 if (tbl == NULL || size < 0 || (size && addr == NULL)) {
235 errno = EINVAL;
236 return (-1);
237 }
238 bzero(&io, sizeof io);
239 io.pfrio_flags = flags;
240 io.pfrio_table = *tbl;
241 io.pfrio_buffer = addr;
242 io.pfrio_esize = sizeof(*addr);
243 io.pfrio_size = size;
244 io.pfrio_size2 = (size2 != NULL) ? *size2 : 0;
245 if (ioctl(dev, DIOCRSETADDRS, &io) == -1)
246 return (-1);
247 if (nadd != NULL)
248 *nadd = io.pfrio_nadd;
249 if (ndel != NULL)
250 *ndel = io.pfrio_ndel;
251 if (nchange != NULL)
252 *nchange = io.pfrio_nchange;
253 if (size2 != NULL)
254 *size2 = io.pfrio_size2;
255 return (0);
256 }
257
258 int
pfr_get_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int * size,int flags)259 pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
260 int flags)
261 {
262 struct pfioc_table io;
263
264 if (tbl == NULL || size == NULL || *size < 0 ||
265 (*size && addr == NULL)) {
266 errno = EINVAL;
267 return (-1);
268 }
269 bzero(&io, sizeof io);
270 io.pfrio_flags = flags;
271 io.pfrio_table = *tbl;
272 io.pfrio_buffer = addr;
273 io.pfrio_esize = sizeof(*addr);
274 io.pfrio_size = *size;
275 if (ioctl(dev, DIOCRGETADDRS, &io) == -1)
276 return (-1);
277 *size = io.pfrio_size;
278 return (0);
279 }
280
281 int
pfr_get_astats(struct pfr_table * tbl,struct pfr_astats * addr,int * size,int flags)282 pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
283 int flags)
284 {
285 struct pfioc_table io;
286
287 if (tbl == NULL || size == NULL || *size < 0 ||
288 (*size && addr == NULL)) {
289 errno = EINVAL;
290 return (-1);
291 }
292 bzero(&io, sizeof io);
293 io.pfrio_flags = flags;
294 io.pfrio_table = *tbl;
295 io.pfrio_buffer = addr;
296 io.pfrio_esize = sizeof(*addr);
297 io.pfrio_size = *size;
298 if (ioctl(dev, DIOCRGETASTATS, &io) == -1)
299 return (-1);
300 *size = io.pfrio_size;
301 return (0);
302 }
303
304 int
pfr_clr_tstats(struct pfr_table * tbl,int size,int * nzero,int flags)305 pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
306 {
307 struct pfioc_table io;
308
309 if (size < 0 || (size && !tbl)) {
310 errno = EINVAL;
311 return (-1);
312 }
313 bzero(&io, sizeof io);
314 io.pfrio_flags = flags;
315 io.pfrio_buffer = tbl;
316 io.pfrio_esize = sizeof(*tbl);
317 io.pfrio_size = size;
318 if (ioctl(dev, DIOCRCLRTSTATS, &io) == -1)
319 return (-1);
320 if (nzero)
321 *nzero = io.pfrio_nzero;
322 return (0);
323 }
324
325 int
pfr_tst_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nmatch,int flags)326 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
327 int *nmatch, int flags)
328 {
329 struct pfioc_table io;
330
331 if (tbl == NULL || size < 0 || (size && addr == NULL)) {
332 errno = EINVAL;
333 return (-1);
334 }
335 bzero(&io, sizeof io);
336 io.pfrio_flags = flags;
337 io.pfrio_table = *tbl;
338 io.pfrio_buffer = addr;
339 io.pfrio_esize = sizeof(*addr);
340 io.pfrio_size = size;
341 if (ioctl(dev, DIOCRTSTADDRS, &io) == -1)
342 return (-1);
343 if (nmatch)
344 *nmatch = io.pfrio_nmatch;
345 return (0);
346 }
347
348 int
pfr_ina_define(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int * naddr,int ticket,int flags)349 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
350 int *nadd, int *naddr, int ticket, int flags)
351 {
352 struct pfioc_table io;
353
354 if (tbl == NULL || size < 0 || (size && addr == NULL)) {
355 errno = EINVAL;
356 return (-1);
357 }
358 bzero(&io, sizeof io);
359 io.pfrio_flags = flags;
360 io.pfrio_table = *tbl;
361 io.pfrio_buffer = addr;
362 io.pfrio_esize = sizeof(*addr);
363 io.pfrio_size = size;
364 io.pfrio_ticket = ticket;
365 if (ioctl(dev, DIOCRINADEFINE, &io) == -1)
366 return (-1);
367 if (nadd != NULL)
368 *nadd = io.pfrio_nadd;
369 if (naddr != NULL)
370 *naddr = io.pfrio_naddr;
371 return (0);
372 }
373
374 /* interface management code */
375
376 int
pfi_get_ifaces(const char * filter,struct pfi_kif * buf,int * size)377 pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size)
378 {
379 struct pfioc_iface io;
380
381 if (size == NULL || *size < 0 || (*size && buf == NULL)) {
382 errno = EINVAL;
383 return (-1);
384 }
385 bzero(&io, sizeof io);
386 if (filter != NULL)
387 if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >=
388 sizeof(io.pfiio_name)) {
389 errno = EINVAL;
390 return (-1);
391 }
392 io.pfiio_buffer = buf;
393 io.pfiio_esize = sizeof(*buf);
394 io.pfiio_size = *size;
395 if (ioctl(dev, DIOCIGETIFACES, &io) == -1)
396 return (-1);
397 *size = io.pfiio_size;
398 return (0);
399 }
400
401 /* buffer management code */
402
403 size_t buf_esize[PFRB_MAX] = { 0,
404 sizeof(struct pfr_table), sizeof(struct pfr_tstats),
405 sizeof(struct pfr_addr), sizeof(struct pfr_astats),
406 sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e)
407 };
408
409 /*
410 * add one element to the buffer
411 */
412 int
pfr_buf_add(struct pfr_buffer * b,const void * e)413 pfr_buf_add(struct pfr_buffer *b, const void *e)
414 {
415 size_t bs;
416
417 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX ||
418 e == NULL) {
419 errno = EINVAL;
420 return (-1);
421 }
422 bs = buf_esize[b->pfrb_type];
423 if (b->pfrb_size == b->pfrb_msize)
424 if (pfr_buf_grow(b, 0))
425 return (-1);
426 memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs);
427 b->pfrb_size++;
428 return (0);
429 }
430
431 /*
432 * return next element of the buffer (or first one if prev is NULL)
433 * see PFRB_FOREACH macro
434 */
435 void *
pfr_buf_next(struct pfr_buffer * b,const void * prev)436 pfr_buf_next(struct pfr_buffer *b, const void *prev)
437 {
438 size_t bs;
439
440 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX)
441 return (NULL);
442 if (b->pfrb_size == 0)
443 return (NULL);
444 if (prev == NULL)
445 return (b->pfrb_caddr);
446 bs = buf_esize[b->pfrb_type];
447 if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1)
448 return (NULL);
449 return (((caddr_t)prev) + bs);
450 }
451
452 /*
453 * minsize:
454 * 0: make the buffer somewhat bigger
455 * n: make room for "n" entries in the buffer
456 */
457 int
pfr_buf_grow(struct pfr_buffer * b,int minsize)458 pfr_buf_grow(struct pfr_buffer *b, int minsize)
459 {
460 caddr_t p;
461 size_t bs;
462
463 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) {
464 errno = EINVAL;
465 return (-1);
466 }
467 if (minsize != 0 && minsize <= b->pfrb_msize)
468 return (0);
469 bs = buf_esize[b->pfrb_type];
470 if (!b->pfrb_msize) {
471 if (minsize < 64)
472 minsize = 64;
473 }
474 if (minsize == 0)
475 minsize = b->pfrb_msize * 2;
476 p = reallocarray(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 return (0);
483 }
484
485 /*
486 * reset buffer and free memory.
487 */
488 void
pfr_buf_clear(struct pfr_buffer * b)489 pfr_buf_clear(struct pfr_buffer *b)
490 {
491 if (b == NULL)
492 return;
493 free(b->pfrb_caddr);
494 b->pfrb_caddr = NULL;
495 b->pfrb_size = b->pfrb_msize = 0;
496 }
497
498 int
pfr_buf_load(struct pfr_buffer * b,char * file,int nonetwork,int opts)499 pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork, int opts)
500 {
501 FILE *fp;
502 char buf[BUF_SIZE];
503 int rv;
504 int ev = 0;
505
506 if (file == NULL)
507 return (0);
508 if (!strcmp(file, "-"))
509 fp = stdin;
510 else {
511 fp = pfctl_fopen(file, "r");
512 if (fp == NULL)
513 return (-1);
514 }
515 while ((rv = pfr_next_token(buf, fp)) == 1)
516 if ((ev = append_addr(b, buf, nonetwork, opts)) == -1) {
517 rv = -1;
518 break;
519 }
520 if (ev == 1) /* expected further append_addr call */
521 rv = -1;
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((unsigned char)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((unsigned char)next_ch));
556 if (i >= BUF_SIZE) {
557 errno = EINVAL;
558 return (-1);
559 }
560 buf[i] = '\0';
561 return (1);
562 }
563