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