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