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