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
pfr_clr_tables(struct pfr_table * filter,int * ndel,int flags)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
pfr_add_tables(struct pfr_table * tbl,int size,int * nadd,int flags)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
pfr_del_tables(struct pfr_table * tbl,int size,int * ndel,int flags)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
pfr_get_tables(struct pfr_table * filter,struct pfr_table * tbl,int * size,int flags)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
pfr_get_tstats(struct pfr_table * filter,struct pfr_tstats * tbl,int * size,int flags)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
pfr_clr_addrs(struct pfr_table * tbl,int * ndel,int flags)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
pfr_add_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int flags)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
pfr_del_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * ndel,int flags)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
pfr_set_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * size2,int * nadd,int * ndel,int * nchange,int flags)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
pfr_get_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int * size,int flags)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
pfr_get_astats(struct pfr_table * tbl,struct pfr_astats * addr,int * size,int flags)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
pfr_clr_tstats(struct pfr_table * tbl,int size,int * nzero,int flags)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
pfr_tst_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nmatch,int flags)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
pfr_ina_define(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int * naddr,int ticket,int flags)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
pfi_get_ifaces(const char * filter,struct pfi_kif * buf,int * size)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 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
pfr_buf_add(struct pfr_buffer * b,const void * e)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 *
pfr_buf_next(struct pfr_buffer * b,const void * prev)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
pfr_buf_grow(struct pfr_buffer * b,int minsize)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
pfr_buf_clear(struct pfr_buffer * b)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
pfr_buf_load(struct pfr_buffer * b,char * file,int nonetwork,int (* append_addr)(struct pfr_buffer *,char *,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
pfr_next_token(char buf[BUF_SIZE],FILE * fp)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 *
pfr_strerror(int errnum)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