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