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