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