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