Home | History | Annotate | Line # | Download | only in pfctl
      1 /*	$NetBSD: pfctl_radix.c,v 1.6 2023/08/01 07:04:14 mrg Exp $	*/
      2 /*	$OpenBSD: pfctl_radix.c,v 1.27 2005/05/21 21:03:58 henning 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 #include <net/if.h>
     39 #include <net/pfvar.h>
     40 
     41 #include <errno.h>
     42 #include <string.h>
     43 #include <ctype.h>
     44 #include <stdio.h>
     45 #include <stdlib.h>
     46 #include <limits.h>
     47 #include <err.h>
     48 
     49 #include "pfctl.h"
     50 
     51 #define BUF_SIZE 256
     52 
     53 extern int dev;
     54 
     55 static int	 pfr_next_token(char buf[BUF_SIZE], FILE *);
     56 
     57 
     58 int
     59 pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
     60 {
     61 	struct pfioc_table io;
     62 
     63 	bzero(&io, sizeof io);
     64 	io.pfrio_flags = flags;
     65 	if (filter != NULL)
     66 		io.pfrio_table = *filter;
     67 	if (ioctl(dev, DIOCRCLRTABLES, &io))
     68 		return (-1);
     69 	if (ndel != NULL)
     70 		*ndel = io.pfrio_ndel;
     71 	return (0);
     72 }
     73 
     74 int
     75 pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
     76 {
     77 	struct pfioc_table io;
     78 
     79 	if (size < 0 || (size && tbl == NULL)) {
     80 		errno = EINVAL;
     81 		return (-1);
     82 	}
     83 	bzero(&io, sizeof io);
     84 	io.pfrio_flags = flags;
     85 	io.pfrio_buffer = tbl;
     86 	io.pfrio_esize = sizeof(*tbl);
     87 	io.pfrio_size = size;
     88 	if (ioctl(dev, DIOCRADDTABLES, &io))
     89 		return (-1);
     90 	if (nadd != NULL)
     91 		*nadd = io.pfrio_nadd;
     92 	return (0);
     93 }
     94 
     95 int
     96 pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
     97 {
     98 	struct pfioc_table io;
     99 
    100 	if (size < 0 || (size && tbl == NULL)) {
    101 		errno = EINVAL;
    102 		return (-1);
    103 	}
    104 	bzero(&io, sizeof io);
    105 	io.pfrio_flags = flags;
    106 	io.pfrio_buffer = tbl;
    107 	io.pfrio_esize = sizeof(*tbl);
    108 	io.pfrio_size = size;
    109 	if (ioctl(dev, DIOCRDELTABLES, &io))
    110 		return (-1);
    111 	if (ndel != NULL)
    112 		*ndel = io.pfrio_ndel;
    113 	return (0);
    114 }
    115 
    116 int
    117 pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
    118 	int flags)
    119 {
    120 	struct pfioc_table io;
    121 
    122 	if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
    123 		errno = EINVAL;
    124 		return (-1);
    125 	}
    126 	bzero(&io, sizeof io);
    127 	io.pfrio_flags = flags;
    128 	if (filter != NULL)
    129 		io.pfrio_table = *filter;
    130 	io.pfrio_buffer = tbl;
    131 	io.pfrio_esize = sizeof(*tbl);
    132 	io.pfrio_size = *size;
    133 	if (ioctl(dev, DIOCRGETTABLES, &io))
    134 		return (-1);
    135 	*size = io.pfrio_size;
    136 	return (0);
    137 }
    138 
    139 int
    140 pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *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, DIOCRGETTSTATS, &io))
    157 		return (-1);
    158 	*size = io.pfrio_size;
    159 	return (0);
    160 }
    161 
    162 int
    163 pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
    164 {
    165 	struct pfioc_table io;
    166 
    167 	if (tbl == NULL) {
    168 		errno = EINVAL;
    169 		return (-1);
    170 	}
    171 	bzero(&io, sizeof io);
    172 	io.pfrio_flags = flags;
    173 	io.pfrio_table = *tbl;
    174 	if (ioctl(dev, DIOCRCLRADDRS, &io))
    175 		return (-1);
    176 	if (ndel != NULL)
    177 		*ndel = io.pfrio_ndel;
    178 	return (0);
    179 }
    180 
    181 int
    182 pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
    183     int *nadd, int flags)
    184 {
    185 	struct pfioc_table io;
    186 
    187 	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
    188 		errno = EINVAL;
    189 		return (-1);
    190 	}
    191 	bzero(&io, sizeof io);
    192 	io.pfrio_flags = flags;
    193 	io.pfrio_table = *tbl;
    194 	io.pfrio_buffer = addr;
    195 	io.pfrio_esize = sizeof(*addr);
    196 	io.pfrio_size = size;
    197 	if (ioctl(dev, DIOCRADDADDRS, &io))
    198 		return (-1);
    199 	if (nadd != NULL)
    200 		*nadd = io.pfrio_nadd;
    201 	return (0);
    202 }
    203 
    204 int
    205 pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
    206     int *ndel, int flags)
    207 {
    208 	struct pfioc_table io;
    209 
    210 	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
    211 		errno = EINVAL;
    212 		return (-1);
    213 	}
    214 	bzero(&io, sizeof io);
    215 	io.pfrio_flags = flags;
    216 	io.pfrio_table = *tbl;
    217 	io.pfrio_buffer = addr;
    218 	io.pfrio_esize = sizeof(*addr);
    219 	io.pfrio_size = size;
    220 	if (ioctl(dev, DIOCRDELADDRS, &io))
    221 		return (-1);
    222 	if (ndel != NULL)
    223 		*ndel = io.pfrio_ndel;
    224 	return (0);
    225 }
    226 
    227 int
    228 pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
    229     int *size2, int *nadd, int *ndel, int *nchange, int flags)
    230 {
    231 	struct pfioc_table io;
    232 
    233 	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
    234 		errno = EINVAL;
    235 		return (-1);
    236 	}
    237 	bzero(&io, sizeof io);
    238 	io.pfrio_flags = flags;
    239 	io.pfrio_table = *tbl;
    240 	io.pfrio_buffer = addr;
    241 	io.pfrio_esize = sizeof(*addr);
    242 	io.pfrio_size = size;
    243 	io.pfrio_size2 = (size2 != NULL) ? *size2 : 0;
    244 	if (ioctl(dev, DIOCRSETADDRS, &io))
    245 		return (-1);
    246 	if (nadd != NULL)
    247 		*nadd = io.pfrio_nadd;
    248 	if (ndel != NULL)
    249 		*ndel = io.pfrio_ndel;
    250 	if (nchange != NULL)
    251 		*nchange = io.pfrio_nchange;
    252 	if (size2 != NULL)
    253 		*size2 = io.pfrio_size2;
    254 	return (0);
    255 }
    256 
    257 int
    258 pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
    259     int flags)
    260 {
    261 	struct pfioc_table io;
    262 
    263 	if (tbl == NULL || size == NULL || *size < 0 ||
    264 	    (*size && addr == NULL)) {
    265 		errno = EINVAL;
    266 		return (-1);
    267 	}
    268 	bzero(&io, sizeof io);
    269 	io.pfrio_flags = flags;
    270 	io.pfrio_table = *tbl;
    271 	io.pfrio_buffer = addr;
    272 	io.pfrio_esize = sizeof(*addr);
    273 	io.pfrio_size = *size;
    274 	if (ioctl(dev, DIOCRGETADDRS, &io))
    275 		return (-1);
    276 	*size = io.pfrio_size;
    277 	return (0);
    278 }
    279 
    280 int
    281 pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
    282     int flags)
    283 {
    284 	struct pfioc_table io;
    285 
    286 	if (tbl == NULL || size == NULL || *size < 0 ||
    287 	    (*size && addr == NULL)) {
    288 		errno = EINVAL;
    289 		return (-1);
    290 	}
    291 	bzero(&io, sizeof io);
    292 	io.pfrio_flags = flags;
    293 	io.pfrio_table = *tbl;
    294 	io.pfrio_buffer = addr;
    295 	io.pfrio_esize = sizeof(*addr);
    296 	io.pfrio_size = *size;
    297 	if (ioctl(dev, DIOCRGETASTATS, &io))
    298 		return (-1);
    299 	*size = io.pfrio_size;
    300 	return (0);
    301 }
    302 
    303 int
    304 pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
    305     int *nzero, int flags)
    306 {
    307 	struct pfioc_table io;
    308 
    309 	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
    310 		errno = EINVAL;
    311 		return (-1);
    312 	}
    313 	bzero(&io, sizeof io);
    314 	io.pfrio_flags = flags;
    315 	io.pfrio_table = *tbl;
    316 	io.pfrio_buffer = addr;
    317 	io.pfrio_esize = sizeof(*addr);
    318 	io.pfrio_size = size;
    319 	if (ioctl(dev, DIOCRCLRASTATS, &io))
    320 		return (-1);
    321 	if (nzero != NULL)
    322 		*nzero = io.pfrio_nzero;
    323 	return (0);
    324 }
    325 
    326 int
    327 pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
    328 {
    329 	struct pfioc_table io;
    330 
    331 	if (size < 0 || (size && !tbl)) {
    332 		errno = EINVAL;
    333 		return (-1);
    334 	}
    335 	bzero(&io, sizeof io);
    336 	io.pfrio_flags = flags;
    337 	io.pfrio_buffer = tbl;
    338 	io.pfrio_esize = sizeof(*tbl);
    339 	io.pfrio_size = size;
    340 	if (ioctl(dev, DIOCRCLRTSTATS, &io))
    341 		return (-1);
    342 	if (nzero)
    343 		*nzero = io.pfrio_nzero;
    344 	return (0);
    345 }
    346 
    347 int
    348 pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag,
    349     int *nchange, int *ndel, int flags)
    350 {
    351 	struct pfioc_table io;
    352 
    353 	if (size < 0 || (size && !tbl)) {
    354 		errno = EINVAL;
    355 		return (-1);
    356 	}
    357 	bzero(&io, sizeof io);
    358 	io.pfrio_flags = flags;
    359 	io.pfrio_buffer = tbl;
    360 	io.pfrio_esize = sizeof(*tbl);
    361 	io.pfrio_size = size;
    362 	io.pfrio_setflag = setflag;
    363 	io.pfrio_clrflag = clrflag;
    364 	if (ioctl(dev, DIOCRSETTFLAGS, &io))
    365 		return (-1);
    366 	if (nchange)
    367 		*nchange = io.pfrio_nchange;
    368 	if (ndel)
    369 		*ndel = io.pfrio_ndel;
    370 	return (0);
    371 }
    372 
    373 int
    374 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
    375     int *nmatch, int flags)
    376 {
    377 	struct pfioc_table io;
    378 
    379 	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
    380 		errno = EINVAL;
    381 		return (-1);
    382 	}
    383 	bzero(&io, sizeof io);
    384 	io.pfrio_flags = flags;
    385 	io.pfrio_table = *tbl;
    386 	io.pfrio_buffer = addr;
    387 	io.pfrio_esize = sizeof(*addr);
    388 	io.pfrio_size = size;
    389 	if (ioctl(dev, DIOCRTSTADDRS, &io))
    390 		return (-1);
    391 	if (nmatch)
    392 		*nmatch = io.pfrio_nmatch;
    393 	return (0);
    394 }
    395 
    396 int
    397 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
    398     int *nadd, int *naddr, int ticket, int flags)
    399 {
    400 	struct pfioc_table io;
    401 
    402 	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
    403 		errno = EINVAL;
    404 		return (-1);
    405 	}
    406 	bzero(&io, sizeof io);
    407 	io.pfrio_flags = flags;
    408 	io.pfrio_table = *tbl;
    409 	io.pfrio_buffer = addr;
    410 	io.pfrio_esize = sizeof(*addr);
    411 	io.pfrio_size = size;
    412 	io.pfrio_ticket = ticket;
    413 	if (ioctl(dev, DIOCRINADEFINE, &io))
    414 		return (-1);
    415 	if (nadd != NULL)
    416 		*nadd = io.pfrio_nadd;
    417 	if (naddr != NULL)
    418 		*naddr = io.pfrio_naddr;
    419 	return (0);
    420 }
    421 
    422 /* interface management code */
    423 
    424 int
    425 pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size)
    426 {
    427 	struct pfioc_iface io;
    428 
    429 	if (size == NULL || *size < 0 || (*size && buf == NULL)) {
    430 		errno = EINVAL;
    431 		return (-1);
    432 	}
    433 	bzero(&io, sizeof io);
    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_kif), 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((unsigned char)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((unsigned char)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