Home | History | Annotate | Line # | Download | only in pfctl
pfctl_radix.c revision 1.4
      1 /*	$NetBSD: pfctl_radix.c,v 1.4 2004/11/14 11:26:48 yamt Exp $	*/
      2 /*	$OpenBSD: pfctl_radix.c,v 1.26 2004/06/14 20:44:22 cedric Exp $ */
      3 
      4 /*
      5  * Copyright (c) 2002 Cedric Berger
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  *    - Redistributions of source code must retain the above copyright
     13  *      notice, this list of conditions and the following disclaimer.
     14  *    - Redistributions in binary form must reproduce the above
     15  *      copyright notice, this list of conditions and the following
     16  *      disclaimer in the documentation and/or other materials provided
     17  *      with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     23  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  *
     32  */
     33 
     34 #include <sys/types.h>
     35 #include <sys/ioctl.h>
     36 #include <sys/socket.h>
     37 
     38 #ifdef __NetBSD__
     39 #include <netinet/in.h>
     40 #endif
     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 
     62 int
     63 pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
     64 {
     65 	struct pfioc_table io;
     66 
     67 	bzero(&io, sizeof io);
     68 	io.pfrio_flags = flags;
     69 	if (filter != NULL)
     70 		io.pfrio_table = *filter;
     71 	if (ioctl(dev, DIOCRCLRTABLES, &io))
     72 		return (-1);
     73 	if (ndel != NULL)
     74 		*ndel = io.pfrio_ndel;
     75 	return (0);
     76 }
     77 
     78 int
     79 pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
     80 {
     81 	struct pfioc_table io;
     82 
     83 	if (size < 0 || (size && tbl == NULL)) {
     84 		errno = EINVAL;
     85 		return (-1);
     86 	}
     87 	bzero(&io, sizeof io);
     88 	io.pfrio_flags = flags;
     89 	io.pfrio_buffer = tbl;
     90 	io.pfrio_esize = sizeof(*tbl);
     91 	io.pfrio_size = size;
     92 	if (ioctl(dev, DIOCRADDTABLES, &io))
     93 		return (-1);
     94 	if (nadd != NULL)
     95 		*nadd = io.pfrio_nadd;
     96 	return (0);
     97 }
     98 
     99 int
    100 pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
    101 {
    102 	struct pfioc_table io;
    103 
    104 	if (size < 0 || (size && tbl == NULL)) {
    105 		errno = EINVAL;
    106 		return (-1);
    107 	}
    108 	bzero(&io, sizeof io);
    109 	io.pfrio_flags = flags;
    110 	io.pfrio_buffer = tbl;
    111 	io.pfrio_esize = sizeof(*tbl);
    112 	io.pfrio_size = size;
    113 	if (ioctl(dev, DIOCRDELTABLES, &io))
    114 		return (-1);
    115 	if (ndel != NULL)
    116 		*ndel = io.pfrio_ndel;
    117 	return (0);
    118 }
    119 
    120 int
    121 pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
    122 	int flags)
    123 {
    124 	struct pfioc_table io;
    125 
    126 	if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
    127 		errno = EINVAL;
    128 		return (-1);
    129 	}
    130 	bzero(&io, sizeof io);
    131 	io.pfrio_flags = flags;
    132 	if (filter != NULL)
    133 		io.pfrio_table = *filter;
    134 	io.pfrio_buffer = tbl;
    135 	io.pfrio_esize = sizeof(*tbl);
    136 	io.pfrio_size = *size;
    137 	if (ioctl(dev, DIOCRGETTABLES, &io))
    138 		return (-1);
    139 	*size = io.pfrio_size;
    140 	return (0);
    141 }
    142 
    143 int
    144 pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
    145 	int flags)
    146 {
    147 	struct pfioc_table io;
    148 
    149 	if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
    150 		errno = EINVAL;
    151 		return (-1);
    152 	}
    153 	bzero(&io, sizeof io);
    154 	io.pfrio_flags = flags;
    155 	if (filter != NULL)
    156 		io.pfrio_table = *filter;
    157 	io.pfrio_buffer = tbl;
    158 	io.pfrio_esize = sizeof(*tbl);
    159 	io.pfrio_size = *size;
    160 	if (ioctl(dev, DIOCRGETTSTATS, &io))
    161 		return (-1);
    162 	*size = io.pfrio_size;
    163 	return (0);
    164 }
    165 
    166 int
    167 pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
    168 {
    169 	struct pfioc_table io;
    170 
    171 	if (tbl == NULL) {
    172 		errno = EINVAL;
    173 		return (-1);
    174 	}
    175 	bzero(&io, sizeof io);
    176 	io.pfrio_flags = flags;
    177 	io.pfrio_table = *tbl;
    178 	if (ioctl(dev, DIOCRCLRADDRS, &io))
    179 		return (-1);
    180 	if (ndel != NULL)
    181 		*ndel = io.pfrio_ndel;
    182 	return (0);
    183 }
    184 
    185 int
    186 pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
    187     int *nadd, int flags)
    188 {
    189 	struct pfioc_table io;
    190 
    191 	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
    192 		errno = EINVAL;
    193 		return (-1);
    194 	}
    195 	bzero(&io, sizeof io);
    196 	io.pfrio_flags = flags;
    197 	io.pfrio_table = *tbl;
    198 	io.pfrio_buffer = addr;
    199 	io.pfrio_esize = sizeof(*addr);
    200 	io.pfrio_size = size;
    201 	if (ioctl(dev, DIOCRADDADDRS, &io))
    202 		return (-1);
    203 	if (nadd != NULL)
    204 		*nadd = io.pfrio_nadd;
    205 	return (0);
    206 }
    207 
    208 int
    209 pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
    210     int *ndel, int flags)
    211 {
    212 	struct pfioc_table io;
    213 
    214 	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
    215 		errno = EINVAL;
    216 		return (-1);
    217 	}
    218 	bzero(&io, sizeof io);
    219 	io.pfrio_flags = flags;
    220 	io.pfrio_table = *tbl;
    221 	io.pfrio_buffer = addr;
    222 	io.pfrio_esize = sizeof(*addr);
    223 	io.pfrio_size = size;
    224 	if (ioctl(dev, DIOCRDELADDRS, &io))
    225 		return (-1);
    226 	if (ndel != NULL)
    227 		*ndel = io.pfrio_ndel;
    228 	return (0);
    229 }
    230 
    231 int
    232 pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
    233     int *size2, int *nadd, int *ndel, int *nchange, int flags)
    234 {
    235 	struct pfioc_table io;
    236 
    237 	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
    238 		errno = EINVAL;
    239 		return (-1);
    240 	}
    241 	bzero(&io, sizeof io);
    242 	io.pfrio_flags = flags;
    243 	io.pfrio_table = *tbl;
    244 	io.pfrio_buffer = addr;
    245 	io.pfrio_esize = sizeof(*addr);
    246 	io.pfrio_size = size;
    247 	io.pfrio_size2 = (size2 != NULL) ? *size2 : 0;
    248 	if (ioctl(dev, DIOCRSETADDRS, &io))
    249 		return (-1);
    250 	if (nadd != NULL)
    251 		*nadd = io.pfrio_nadd;
    252 	if (ndel != NULL)
    253 		*ndel = io.pfrio_ndel;
    254 	if (nchange != NULL)
    255 		*nchange = io.pfrio_nchange;
    256 	if (size2 != NULL)
    257 		*size2 = io.pfrio_size2;
    258 	return (0);
    259 }
    260 
    261 int
    262 pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
    263     int flags)
    264 {
    265 	struct pfioc_table io;
    266 
    267 	if (tbl == NULL || size == NULL || *size < 0 ||
    268 	    (*size && addr == NULL)) {
    269 		errno = EINVAL;
    270 		return (-1);
    271 	}
    272 	bzero(&io, sizeof io);
    273 	io.pfrio_flags = flags;
    274 	io.pfrio_table = *tbl;
    275 	io.pfrio_buffer = addr;
    276 	io.pfrio_esize = sizeof(*addr);
    277 	io.pfrio_size = *size;
    278 	if (ioctl(dev, DIOCRGETADDRS, &io))
    279 		return (-1);
    280 	*size = io.pfrio_size;
    281 	return (0);
    282 }
    283 
    284 int
    285 pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
    286     int flags)
    287 {
    288 	struct pfioc_table io;
    289 
    290 	if (tbl == NULL || size == NULL || *size < 0 ||
    291 	    (*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, DIOCRGETASTATS, &io))
    302 		return (-1);
    303 	*size = io.pfrio_size;
    304 	return (0);
    305 }
    306 
    307 int
    308 pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
    309     int *nzero, int flags)
    310 {
    311 	struct pfioc_table io;
    312 
    313 	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
    314 		errno = EINVAL;
    315 		return (-1);
    316 	}
    317 	bzero(&io, sizeof io);
    318 	io.pfrio_flags = flags;
    319 	io.pfrio_table = *tbl;
    320 	io.pfrio_buffer = addr;
    321 	io.pfrio_esize = sizeof(*addr);
    322 	io.pfrio_size = size;
    323 	if (ioctl(dev, DIOCRCLRASTATS, &io))
    324 		return (-1);
    325 	if (nzero != NULL)
    326 		*nzero = io.pfrio_nzero;
    327 	return (0);
    328 }
    329 
    330 int
    331 pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
    332 {
    333 	struct pfioc_table io;
    334 
    335 	if (size < 0 || (size && !tbl)) {
    336 		errno = EINVAL;
    337 		return (-1);
    338 	}
    339 	bzero(&io, sizeof io);
    340 	io.pfrio_flags = flags;
    341 	io.pfrio_buffer = tbl;
    342 	io.pfrio_esize = sizeof(*tbl);
    343 	io.pfrio_size = size;
    344 	if (ioctl(dev, DIOCRCLRTSTATS, &io))
    345 		return (-1);
    346 	if (nzero)
    347 		*nzero = io.pfrio_nzero;
    348 	return (0);
    349 }
    350 
    351 int
    352 pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag,
    353     int *nchange, int *ndel, int flags)
    354 {
    355 	struct pfioc_table io;
    356 
    357 	if (size < 0 || (size && !tbl)) {
    358 		errno = EINVAL;
    359 		return (-1);
    360 	}
    361 	bzero(&io, sizeof io);
    362 	io.pfrio_flags = flags;
    363 	io.pfrio_buffer = tbl;
    364 	io.pfrio_esize = sizeof(*tbl);
    365 	io.pfrio_size = size;
    366 	io.pfrio_setflag = setflag;
    367 	io.pfrio_clrflag = clrflag;
    368 	if (ioctl(dev, DIOCRSETTFLAGS, &io))
    369 		return (-1);
    370 	if (nchange)
    371 		*nchange = io.pfrio_nchange;
    372 	if (ndel)
    373 		*ndel = io.pfrio_ndel;
    374 	return (0);
    375 }
    376 
    377 int
    378 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
    379     int *nmatch, int flags)
    380 {
    381 	struct pfioc_table io;
    382 
    383 	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
    384 		errno = EINVAL;
    385 		return (-1);
    386 	}
    387 	bzero(&io, sizeof io);
    388 	io.pfrio_flags = flags;
    389 	io.pfrio_table = *tbl;
    390 	io.pfrio_buffer = addr;
    391 	io.pfrio_esize = sizeof(*addr);
    392 	io.pfrio_size = size;
    393 	if (ioctl(dev, DIOCRTSTADDRS, &io))
    394 		return (-1);
    395 	if (nmatch)
    396 		*nmatch = io.pfrio_nmatch;
    397 	return (0);
    398 }
    399 
    400 int
    401 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
    402     int *nadd, int *naddr, int ticket, int flags)
    403 {
    404 	struct pfioc_table io;
    405 
    406 	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
    407 		errno = EINVAL;
    408 		return (-1);
    409 	}
    410 	bzero(&io, sizeof io);
    411 	io.pfrio_flags = flags;
    412 	io.pfrio_table = *tbl;
    413 	io.pfrio_buffer = addr;
    414 	io.pfrio_esize = sizeof(*addr);
    415 	io.pfrio_size = size;
    416 	io.pfrio_ticket = ticket;
    417 	if (ioctl(dev, DIOCRINADEFINE, &io))
    418 		return (-1);
    419 	if (nadd != NULL)
    420 		*nadd = io.pfrio_nadd;
    421 	if (naddr != NULL)
    422 		*naddr = io.pfrio_naddr;
    423 	return (0);
    424 }
    425 
    426 /* interface management code */
    427 
    428 int
    429 pfi_get_ifaces(const char *filter, struct pfi_if *buf, int *size, int flags)
    430 {
    431 	struct pfioc_iface io;
    432 
    433 	if (size == NULL || *size < 0 || (*size && buf == NULL)) {
    434 		errno = EINVAL;
    435 		return (-1);
    436 	}
    437 	bzero(&io, sizeof io);
    438 	io.pfiio_flags = flags;
    439 	if (filter != NULL)
    440 		if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >=
    441 		    sizeof(io.pfiio_name)) {
    442 			errno = EINVAL;
    443 			return (-1);
    444 		}
    445 	io.pfiio_buffer = buf;
    446 	io.pfiio_esize = sizeof(*buf);
    447 	io.pfiio_size = *size;
    448 	if (ioctl(dev, DIOCIGETIFACES, &io))
    449 		return (-1);
    450 	*size = io.pfiio_size;
    451 	return (0);
    452 }
    453 
    454 /* buffer management code */
    455 
    456 size_t buf_esize[PFRB_MAX] = { 0,
    457 	sizeof(struct pfr_table), sizeof(struct pfr_tstats),
    458 	sizeof(struct pfr_addr), sizeof(struct pfr_astats),
    459 	sizeof(struct pfi_if), sizeof(struct pfioc_trans_e)
    460 };
    461 
    462 /*
    463  * add one element to the buffer
    464  */
    465 int
    466 pfr_buf_add(struct pfr_buffer *b, const void *e)
    467 {
    468 	size_t bs;
    469 
    470 	if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX ||
    471 	    e == NULL) {
    472 		errno = EINVAL;
    473 		return (-1);
    474 	}
    475 	bs = buf_esize[b->pfrb_type];
    476 	if (b->pfrb_size == b->pfrb_msize)
    477 		if (pfr_buf_grow(b, 0))
    478 			return (-1);
    479 	memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs);
    480 	b->pfrb_size++;
    481 	return (0);
    482 }
    483 
    484 /*
    485  * return next element of the buffer (or first one if prev is NULL)
    486  * see PFRB_FOREACH macro
    487  */
    488 void *
    489 pfr_buf_next(struct pfr_buffer *b, const void *prev)
    490 {
    491 	size_t bs;
    492 
    493 	if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX)
    494 		return (NULL);
    495 	if (b->pfrb_size == 0)
    496 		return (NULL);
    497 	if (prev == NULL)
    498 		return (b->pfrb_caddr);
    499 	bs = buf_esize[b->pfrb_type];
    500 	if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1)
    501 		return (NULL);
    502 	return (((caddr_t)prev) + bs);
    503 }
    504 
    505 /*
    506  * minsize:
    507  *    0: make the buffer somewhat bigger
    508  *    n: make room for "n" entries in the buffer
    509  */
    510 int
    511 pfr_buf_grow(struct pfr_buffer *b, int minsize)
    512 {
    513 	caddr_t p;
    514 	size_t bs;
    515 
    516 	if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) {
    517 		errno = EINVAL;
    518 		return (-1);
    519 	}
    520 	if (minsize != 0 && minsize <= b->pfrb_msize)
    521 		return (0);
    522 	bs = buf_esize[b->pfrb_type];
    523 	if (!b->pfrb_msize) {
    524 		if (minsize < 64)
    525 			minsize = 64;
    526 		b->pfrb_caddr = calloc(bs, minsize);
    527 		if (b->pfrb_caddr == NULL)
    528 			return (-1);
    529 		b->pfrb_msize = minsize;
    530 	} else {
    531 		if (minsize == 0)
    532 			minsize = b->pfrb_msize * 2;
    533 		if (minsize < 0 || minsize >= SIZE_T_MAX / bs) {
    534 			/* msize overflow */
    535 			errno = ENOMEM;
    536 			return (-1);
    537 		}
    538 		p = realloc(b->pfrb_caddr, minsize * bs);
    539 		if (p == NULL)
    540 			return (-1);
    541 		bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs);
    542 		b->pfrb_caddr = p;
    543 		b->pfrb_msize = minsize;
    544 	}
    545 	return (0);
    546 }
    547 
    548 /*
    549  * reset buffer and free memory.
    550  */
    551 void
    552 pfr_buf_clear(struct pfr_buffer *b)
    553 {
    554 	if (b == NULL)
    555 		return;
    556 	if (b->pfrb_caddr != NULL)
    557 		free(b->pfrb_caddr);
    558 	b->pfrb_caddr = NULL;
    559 	b->pfrb_size = b->pfrb_msize = 0;
    560 }
    561 
    562 int
    563 pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork,
    564     int (*append_addr)(struct pfr_buffer *, char *, int))
    565 {
    566 	FILE	*fp;
    567 	char	 buf[BUF_SIZE];
    568 	int	 rv;
    569 
    570 	if (file == NULL)
    571 		return (0);
    572 	if (!strcmp(file, "-"))
    573 		fp = stdin;
    574 	else {
    575 		fp = pfctl_fopen(file, "r");
    576 		if (fp == NULL)
    577 			return (-1);
    578 	}
    579 	while ((rv = pfr_next_token(buf, fp)) == 1)
    580 		if (append_addr(b, buf, nonetwork)) {
    581 			rv = -1;
    582 			break;
    583 		}
    584 	if (fp != stdin)
    585 		fclose(fp);
    586 	return (rv);
    587 }
    588 
    589 int
    590 pfr_next_token(char buf[BUF_SIZE], FILE *fp)
    591 {
    592 	static char	next_ch = ' ';
    593 	int		i = 0;
    594 
    595 	for (;;) {
    596 		/* skip spaces */
    597 		while (isspace((unsigned char)next_ch) && !feof(fp))
    598 			next_ch = fgetc(fp);
    599 		/* remove from '#' until end of line */
    600 		if (next_ch == '#')
    601 			while (!feof(fp)) {
    602 				next_ch = fgetc(fp);
    603 				if (next_ch == '\n')
    604 					break;
    605 			}
    606 		else
    607 			break;
    608 	}
    609 	if (feof(fp)) {
    610 		next_ch = ' ';
    611 		return (0);
    612 	}
    613 	do {
    614 		if (i < BUF_SIZE)
    615 			buf[i++] = next_ch;
    616 		next_ch = fgetc(fp);
    617 	} while (!feof(fp) && !isspace((unsigned char)next_ch));
    618 	if (i >= BUF_SIZE) {
    619 		errno = EINVAL;
    620 		return (-1);
    621 	}
    622 	buf[i] = '\0';
    623 	return (1);
    624 }
    625 
    626 char *
    627 pfr_strerror(int errnum)
    628 {
    629 	switch (errnum) {
    630 	case ESRCH:
    631 		return "Table does not exist";
    632 	case ENOENT:
    633 		return "Anchor or Ruleset does not exist";
    634 	default:
    635 		return strerror(errnum);
    636 	}
    637 }
    638