]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/pfctl/pfctl_radix.c
pf: backport OpenBSD syntax of "scrub" option for "match" and "pass" rules
[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[BUF_SIZE], 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         int ret;
215
216         ret = pfctl_table_add_addrs(dev, tbl, addr, size, nadd, flags);
217         if (ret) {
218                 errno = ret;
219                 return (-1);
220         }
221         return (0);
222 }
223
224 int
225 pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
226     int *ndel, int flags)
227 {
228         int ret;
229
230         ret = pfctl_table_del_addrs(dev, tbl, addr, size, ndel, flags);
231         if (ret) {
232                 errno = ret;
233                 return (-1);
234         }
235         return (0);
236 }
237
238 int
239 pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
240     int *size2, int *nadd, int *ndel, int *nchange, int flags)
241 {
242         int ret;
243
244         ret = pfctl_table_set_addrs(dev, tbl, addr, size, size2, nadd, ndel,
245             nchange, flags);
246         if (ret) {
247                 errno = ret;
248                 return (-1);
249         }
250         return (0);
251 }
252
253 int
254 pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
255     int flags)
256 {
257         int ret;
258
259         ret = pfctl_table_get_addrs(dev, tbl, addr, size, flags);
260         if (ret) {
261                 errno = ret;
262                 return (-1);
263         }
264         return (0);
265 }
266
267 int
268 pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
269     int flags)
270 {
271         struct pfioc_table io;
272
273         if (tbl == NULL || size == NULL || *size < 0 ||
274             (*size && addr == NULL)) {
275                 errno = EINVAL;
276                 return (-1);
277         }
278         bzero(&io, sizeof io);
279         io.pfrio_flags = flags;
280         io.pfrio_table = *tbl;
281         io.pfrio_buffer = addr;
282         io.pfrio_esize = sizeof(*addr);
283         io.pfrio_size = *size;
284         if (ioctl(dev, DIOCRGETASTATS, &io)) {
285                 pfr_report_error(tbl, &io, "get astats from");
286                 return (-1);
287         }
288         *size = io.pfrio_size;
289         return (0);
290 }
291
292 int
293 pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
294 {
295         struct pfioc_table io;
296
297         if (size < 0 || (size && !tbl)) {
298                 errno = EINVAL;
299                 return (-1);
300         }
301         bzero(&io, sizeof io);
302         io.pfrio_flags = flags;
303         io.pfrio_buffer = tbl;
304         io.pfrio_esize = sizeof(*tbl);
305         io.pfrio_size = size;
306         if (ioctl(dev, DIOCRCLRTSTATS, &io)) {
307                 pfr_report_error(tbl, &io, "clear tstats from");
308                 return (-1);
309         }
310         if (nzero)
311                 *nzero = io.pfrio_nzero;
312         return (0);
313 }
314
315 int
316 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
317     int *nmatch, int flags)
318 {
319         struct pfioc_table io;
320
321         if (tbl == NULL || size < 0 || (size && addr == NULL)) {
322                 errno = EINVAL;
323                 return (-1);
324         }
325         bzero(&io, sizeof io);
326         io.pfrio_flags = flags;
327         io.pfrio_table = *tbl;
328         io.pfrio_buffer = addr;
329         io.pfrio_esize = sizeof(*addr);
330         io.pfrio_size = size;
331         if (ioctl(dev, DIOCRTSTADDRS, &io)) {
332                 pfr_report_error(tbl, &io, "test addresses in");
333                 return (-1);
334         }
335         if (nmatch)
336                 *nmatch = io.pfrio_nmatch;
337         return (0);
338 }
339
340 int
341 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
342     int *nadd, int *naddr, int ticket, int flags)
343 {
344         struct pfioc_table io;
345
346         if (tbl == NULL || size < 0 || (size && addr == NULL)) {
347                 errno = EINVAL;
348                 return (-1);
349         }
350         bzero(&io, sizeof io);
351         io.pfrio_flags = flags;
352         io.pfrio_table = *tbl;
353         io.pfrio_buffer = addr;
354         io.pfrio_esize = sizeof(*addr);
355         io.pfrio_size = size;
356         io.pfrio_ticket = ticket;
357         if (ioctl(dev, DIOCRINADEFINE, &io)) {
358                 pfr_report_error(tbl, &io, "define inactive set table");
359                 return (-1);
360         }
361         if (nadd != NULL)
362                 *nadd = io.pfrio_nadd;
363         if (naddr != NULL)
364                 *naddr = io.pfrio_naddr;
365         return (0);
366 }
367
368 /* interface management code */
369
370 int
371 pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size)
372 {
373         struct pfioc_iface io;
374
375         if (size == NULL || *size < 0 || (*size && buf == NULL)) {
376                 errno = EINVAL;
377                 return (-1);
378         }
379         bzero(&io, sizeof io);
380         if (filter != NULL)
381                 if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >=
382                     sizeof(io.pfiio_name)) {
383                         errno = EINVAL;
384                         return (-1);
385                 }
386         io.pfiio_buffer = buf;
387         io.pfiio_esize = sizeof(*buf);
388         io.pfiio_size = *size;
389         if (ioctl(dev, DIOCIGETIFACES, &io))
390                 return (-1);
391         *size = io.pfiio_size;
392         return (0);
393 }
394
395 /* buffer management code */
396
397 const size_t buf_esize[PFRB_MAX] = { 0,
398         sizeof(struct pfr_table), sizeof(struct pfr_tstats),
399         sizeof(struct pfr_addr), sizeof(struct pfr_astats),
400         sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e)
401 };
402
403 /*
404  * add one element to the buffer
405  */
406 int
407 pfr_buf_add(struct pfr_buffer *b, const void *e)
408 {
409         size_t bs;
410
411         if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX ||
412             e == NULL) {
413                 errno = EINVAL;
414                 return (-1);
415         }
416         bs = buf_esize[b->pfrb_type];
417         if (b->pfrb_size == b->pfrb_msize)
418                 if (pfr_buf_grow(b, 0))
419                         return (-1);
420         memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs);
421         b->pfrb_size++;
422         return (0);
423 }
424
425 /*
426  * return next element of the buffer (or first one if prev is NULL)
427  * see PFRB_FOREACH macro
428  */
429 void *
430 pfr_buf_next(struct pfr_buffer *b, const void *prev)
431 {
432         size_t bs;
433
434         if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX)
435                 return (NULL);
436         if (b->pfrb_size == 0)
437                 return (NULL);
438         if (prev == NULL)
439                 return (b->pfrb_caddr);
440         bs = buf_esize[b->pfrb_type];
441         if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1)
442                 return (NULL);
443         return (((caddr_t)prev) + bs);
444 }
445
446 /*
447  * minsize:
448  *    0: make the buffer somewhat bigger
449  *    n: make room for "n" entries in the buffer
450  */
451 int
452 pfr_buf_grow(struct pfr_buffer *b, int minsize)
453 {
454         caddr_t p;
455         size_t bs;
456
457         if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) {
458                 errno = EINVAL;
459                 return (-1);
460         }
461         if (minsize != 0 && minsize <= b->pfrb_msize)
462                 return (0);
463         bs = buf_esize[b->pfrb_type];
464         if (!b->pfrb_msize) {
465                 if (minsize < 64)
466                         minsize = 64;
467                 b->pfrb_caddr = calloc(bs, minsize);
468                 if (b->pfrb_caddr == NULL)
469                         return (-1);
470                 b->pfrb_msize = minsize;
471         } else {
472                 if (minsize == 0)
473                         minsize = b->pfrb_msize * 2;
474                 if (minsize < 0 || minsize >= SIZE_T_MAX / bs) {
475                         /* msize overflow */
476                         errno = ENOMEM;
477                         return (-1);
478                 }
479                 p = realloc(b->pfrb_caddr, minsize * bs);
480                 if (p == NULL)
481                         return (-1);
482                 bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs);
483                 b->pfrb_caddr = p;
484                 b->pfrb_msize = minsize;
485         }
486         return (0);
487 }
488
489 /*
490  * reset buffer and free memory.
491  */
492 void
493 pfr_buf_clear(struct pfr_buffer *b)
494 {
495         if (b == NULL)
496                 return;
497         if (b->pfrb_caddr != NULL)
498                 free(b->pfrb_caddr);
499         b->pfrb_caddr = NULL;
500         b->pfrb_size = b->pfrb_msize = 0;
501 }
502
503 int
504 pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork,
505     int (*append_addr)(struct pfr_buffer *, char *, int))
506 {
507         FILE    *fp;
508         char     buf[BUF_SIZE];
509         int      rv;
510
511         if (file == NULL)
512                 return (0);
513         if (!strcmp(file, "-"))
514                 fp = stdin;
515         else {
516                 fp = pfctl_fopen(file, "r");
517                 if (fp == NULL)
518                         return (-1);
519         }
520         while ((rv = pfr_next_token(buf, fp)) == 1)
521                 if (append_addr(b, buf, nonetwork)) {
522                         rv = -1;
523                         break;
524                 }
525         if (fp != stdin)
526                 fclose(fp);
527         return (rv);
528 }
529
530 int
531 pfr_next_token(char buf[BUF_SIZE], FILE *fp)
532 {
533         static char     next_ch = ' ';
534         int             i = 0;
535
536         for (;;) {
537                 /* skip spaces */
538                 while (isspace(next_ch) && !feof(fp))
539                         next_ch = fgetc(fp);
540                 /* remove from '#' until end of line */
541                 if (next_ch == '#')
542                         while (!feof(fp)) {
543                                 next_ch = fgetc(fp);
544                                 if (next_ch == '\n')
545                                         break;
546                         }
547                 else
548                         break;
549         }
550         if (feof(fp)) {
551                 next_ch = ' ';
552                 return (0);
553         }
554         do {
555                 if (i < BUF_SIZE)
556                         buf[i++] = next_ch;
557                 next_ch = fgetc(fp);
558         } while (!feof(fp) && !isspace(next_ch));
559         if (i >= BUF_SIZE) {
560                 errno = EINVAL;
561                 return (-1);
562         }
563         buf[i] = '\0';
564         return (1);
565 }
566
567 char *
568 pfr_strerror(int errnum)
569 {
570         switch (errnum) {
571         case ESRCH:
572                 return "Table does not exist";
573         case ENOENT:
574                 return "Anchor or Ruleset does not exist";
575         default:
576                 return strerror(errnum);
577         }
578 }