xref: /openbsd/sbin/pfctl/pfctl_radix.c (revision 1adff8d7)
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