]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/pfctl/pfctl_radix.c
ssh: Update to OpenSSH 9.5p1
[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 #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[BUF_SIZE], FILE *);
58
59 static void
60 pfr_report_error(struct pfr_table *tbl, struct pfioc_table *io,
61     const char *err)
62 {
63         unsigned long maxcount;
64         size_t s;
65
66         s = sizeof(maxcount);
67         if (sysctlbyname("net.pf.request_maxcount", &maxcount, &s, NULL,
68             0) == -1)
69                 return;
70
71         if (io->pfrio_size > maxcount || io->pfrio_size2 > maxcount)
72                 fprintf(stderr, "cannot %s %s: too many elements.\n"
73                     "Consider increasing net.pf.request_maxcount.",
74                     err, tbl->pfrt_name);
75 }
76
77 int
78 pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
79 {
80         struct pfioc_table io;
81
82         bzero(&io, sizeof io);
83         io.pfrio_flags = flags;
84         if (filter != NULL)
85                 io.pfrio_table = *filter;
86         if (ioctl(dev, DIOCRCLRTABLES, &io))
87                 return (-1);
88         if (ndel != NULL)
89                 *ndel = io.pfrio_ndel;
90         return (0);
91 }
92
93 int
94 pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
95 {
96         struct pfioc_table io;
97
98         if (size < 0 || (size && tbl == NULL)) {
99                 errno = EINVAL;
100                 return (-1);
101         }
102         bzero(&io, sizeof io);
103         io.pfrio_flags = flags;
104         io.pfrio_buffer = tbl;
105         io.pfrio_esize = sizeof(*tbl);
106         io.pfrio_size = size;
107         if (ioctl(dev, DIOCRADDTABLES, &io)) {
108                 pfr_report_error(tbl, &io, "add table");
109                 return (-1);
110         }
111         if (nadd != NULL)
112                 *nadd = io.pfrio_nadd;
113         return (0);
114 }
115
116 int
117 pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
118 {
119         struct pfioc_table io;
120
121         if (size < 0 || (size && tbl == NULL)) {
122                 errno = EINVAL;
123                 return (-1);
124         }
125         bzero(&io, sizeof io);
126         io.pfrio_flags = flags;
127         io.pfrio_buffer = tbl;
128         io.pfrio_esize = sizeof(*tbl);
129         io.pfrio_size = size;
130         if (ioctl(dev, DIOCRDELTABLES, &io)) {
131                 pfr_report_error(tbl, &io, "delete table");
132                 return (-1);
133         }
134         if (ndel != NULL)
135                 *ndel = io.pfrio_ndel;
136         return (0);
137 }
138
139 int
140 pfr_get_tables(struct pfr_table *filter, struct pfr_table *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, DIOCRGETTABLES, &io)) {
157                 pfr_report_error(tbl, &io, "get table");
158                 return (-1);
159         }
160         *size = io.pfrio_size;
161         return (0);
162 }
163
164 int
165 pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
166         int flags)
167 {
168         struct pfioc_table io;
169
170         if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
171                 errno = EINVAL;
172                 return (-1);
173         }
174         bzero(&io, sizeof io);
175         io.pfrio_flags = flags;
176         if (filter != NULL)
177                 io.pfrio_table = *filter;
178         io.pfrio_buffer = tbl;
179         io.pfrio_esize = sizeof(*tbl);
180         io.pfrio_size = *size;
181         if (ioctl(dev, DIOCRGETTSTATS, &io)) {
182                 pfr_report_error(filter, &io, "get tstats for");
183                 return (-1);
184         }
185         *size = io.pfrio_size;
186         return (0);
187 }
188
189 int
190 pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
191 {
192         struct pfioc_table io;
193
194         if (tbl == NULL) {
195                 errno = EINVAL;
196                 return (-1);
197         }
198         bzero(&io, sizeof io);
199         io.pfrio_flags = flags;
200         io.pfrio_table = *tbl;
201         if (ioctl(dev, DIOCRCLRADDRS, &io))
202                 return (-1);
203         if (ndel != NULL)
204                 *ndel = io.pfrio_ndel;
205         return (0);
206 }
207
208 int
209 pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
210     int *nadd, int flags)
211 {
212         int ret;
213
214         ret = pfctl_table_add_addrs(dev, tbl, addr, size, nadd, flags);
215         if (ret) {
216                 errno = ret;
217                 return (-1);
218         }
219         return (0);
220 }
221
222 int
223 pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
224     int *ndel, int flags)
225 {
226         int ret;
227
228         ret = pfctl_table_del_addrs(dev, tbl, addr, size, ndel, flags);
229         if (ret) {
230                 errno = ret;
231                 return (-1);
232         }
233         return (0);
234 }
235
236 int
237 pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
238     int *size2, int *nadd, int *ndel, int *nchange, int flags)
239 {
240         int ret;
241
242         ret = pfctl_table_set_addrs(dev, tbl, addr, size, size2, nadd, ndel,
243             nchange, flags);
244         if (ret) {
245                 errno = ret;
246                 return (-1);
247         }
248         return (0);
249 }
250
251 int
252 pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
253     int flags)
254 {
255         int ret;
256
257         ret = pfctl_table_get_addrs(dev, tbl, addr, size, flags);
258         if (ret) {
259                 errno = ret;
260                 return (-1);
261         }
262         return (0);
263 }
264
265 int
266 pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
267     int flags)
268 {
269         struct pfioc_table io;
270
271         if (tbl == NULL || size == NULL || *size < 0 ||
272             (*size && addr == NULL)) {
273                 errno = EINVAL;
274                 return (-1);
275         }
276         bzero(&io, sizeof io);
277         io.pfrio_flags = flags;
278         io.pfrio_table = *tbl;
279         io.pfrio_buffer = addr;
280         io.pfrio_esize = sizeof(*addr);
281         io.pfrio_size = *size;
282         if (ioctl(dev, DIOCRGETASTATS, &io)) {
283                 pfr_report_error(tbl, &io, "get astats from");
284                 return (-1);
285         }
286         *size = io.pfrio_size;
287         return (0);
288 }
289
290 int
291 pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
292 {
293         struct pfioc_table io;
294
295         if (size < 0 || (size && !tbl)) {
296                 errno = EINVAL;
297                 return (-1);
298         }
299         bzero(&io, sizeof io);
300         io.pfrio_flags = flags;
301         io.pfrio_buffer = tbl;
302         io.pfrio_esize = sizeof(*tbl);
303         io.pfrio_size = size;
304         if (ioctl(dev, DIOCRCLRTSTATS, &io)) {
305                 pfr_report_error(tbl, &io, "clear tstats from");
306                 return (-1);
307         }
308         if (nzero)
309                 *nzero = io.pfrio_nzero;
310         return (0);
311 }
312
313 int
314 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
315     int *nmatch, int flags)
316 {
317         struct pfioc_table io;
318
319         if (tbl == NULL || size < 0 || (size && addr == NULL)) {
320                 errno = EINVAL;
321                 return (-1);
322         }
323         bzero(&io, sizeof io);
324         io.pfrio_flags = flags;
325         io.pfrio_table = *tbl;
326         io.pfrio_buffer = addr;
327         io.pfrio_esize = sizeof(*addr);
328         io.pfrio_size = size;
329         if (ioctl(dev, DIOCRTSTADDRS, &io)) {
330                 pfr_report_error(tbl, &io, "test addresses in");
331                 return (-1);
332         }
333         if (nmatch)
334                 *nmatch = io.pfrio_nmatch;
335         return (0);
336 }
337
338 int
339 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
340     int *nadd, int *naddr, int ticket, int flags)
341 {
342         struct pfioc_table io;
343
344         if (tbl == NULL || size < 0 || (size && addr == NULL)) {
345                 errno = EINVAL;
346                 return (-1);
347         }
348         bzero(&io, sizeof io);
349         io.pfrio_flags = flags;
350         io.pfrio_table = *tbl;
351         io.pfrio_buffer = addr;
352         io.pfrio_esize = sizeof(*addr);
353         io.pfrio_size = size;
354         io.pfrio_ticket = ticket;
355         if (ioctl(dev, DIOCRINADEFINE, &io)) {
356                 pfr_report_error(tbl, &io, "define inactive set table");
357                 return (-1);
358         }
359         if (nadd != NULL)
360                 *nadd = io.pfrio_nadd;
361         if (naddr != NULL)
362                 *naddr = io.pfrio_naddr;
363         return (0);
364 }
365
366 /* interface management code */
367
368 int
369 pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size)
370 {
371         struct pfioc_iface io;
372
373         if (size == NULL || *size < 0 || (*size && buf == NULL)) {
374                 errno = EINVAL;
375                 return (-1);
376         }
377         bzero(&io, sizeof io);
378         if (filter != NULL)
379                 if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >=
380                     sizeof(io.pfiio_name)) {
381                         errno = EINVAL;
382                         return (-1);
383                 }
384         io.pfiio_buffer = buf;
385         io.pfiio_esize = sizeof(*buf);
386         io.pfiio_size = *size;
387         if (ioctl(dev, DIOCIGETIFACES, &io))
388                 return (-1);
389         *size = io.pfiio_size;
390         return (0);
391 }
392
393 /* buffer management code */
394
395 const size_t buf_esize[PFRB_MAX] = { 0,
396         sizeof(struct pfr_table), sizeof(struct pfr_tstats),
397         sizeof(struct pfr_addr), sizeof(struct pfr_astats),
398         sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e)
399 };
400
401 /*
402  * add one element to the buffer
403  */
404 int
405 pfr_buf_add(struct pfr_buffer *b, const void *e)
406 {
407         size_t bs;
408
409         if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX ||
410             e == NULL) {
411                 errno = EINVAL;
412                 return (-1);
413         }
414         bs = buf_esize[b->pfrb_type];
415         if (b->pfrb_size == b->pfrb_msize)
416                 if (pfr_buf_grow(b, 0))
417                         return (-1);
418         memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs);
419         b->pfrb_size++;
420         return (0);
421 }
422
423 /*
424  * return next element of the buffer (or first one if prev is NULL)
425  * see PFRB_FOREACH macro
426  */
427 void *
428 pfr_buf_next(struct pfr_buffer *b, const void *prev)
429 {
430         size_t bs;
431
432         if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX)
433                 return (NULL);
434         if (b->pfrb_size == 0)
435                 return (NULL);
436         if (prev == NULL)
437                 return (b->pfrb_caddr);
438         bs = buf_esize[b->pfrb_type];
439         if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1)
440                 return (NULL);
441         return (((caddr_t)prev) + bs);
442 }
443
444 /*
445  * minsize:
446  *    0: make the buffer somewhat bigger
447  *    n: make room for "n" entries in the buffer
448  */
449 int
450 pfr_buf_grow(struct pfr_buffer *b, int minsize)
451 {
452         caddr_t p;
453         size_t bs;
454
455         if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) {
456                 errno = EINVAL;
457                 return (-1);
458         }
459         if (minsize != 0 && minsize <= b->pfrb_msize)
460                 return (0);
461         bs = buf_esize[b->pfrb_type];
462         if (!b->pfrb_msize) {
463                 if (minsize < 64)
464                         minsize = 64;
465                 b->pfrb_caddr = calloc(bs, minsize);
466                 if (b->pfrb_caddr == NULL)
467                         return (-1);
468                 b->pfrb_msize = minsize;
469         } else {
470                 if (minsize == 0)
471                         minsize = b->pfrb_msize * 2;
472                 if (minsize < 0 || minsize >= SIZE_T_MAX / bs) {
473                         /* msize overflow */
474                         errno = ENOMEM;
475                         return (-1);
476                 }
477                 p = realloc(b->pfrb_caddr, minsize * bs);
478                 if (p == NULL)
479                         return (-1);
480                 bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs);
481                 b->pfrb_caddr = p;
482                 b->pfrb_msize = minsize;
483         }
484         return (0);
485 }
486
487 /*
488  * reset buffer and free memory.
489  */
490 void
491 pfr_buf_clear(struct pfr_buffer *b)
492 {
493         if (b == NULL)
494                 return;
495         if (b->pfrb_caddr != NULL)
496                 free(b->pfrb_caddr);
497         b->pfrb_caddr = NULL;
498         b->pfrb_size = b->pfrb_msize = 0;
499 }
500
501 int
502 pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork,
503     int (*append_addr)(struct pfr_buffer *, char *, int))
504 {
505         FILE    *fp;
506         char     buf[BUF_SIZE];
507         int      rv;
508
509         if (file == NULL)
510                 return (0);
511         if (!strcmp(file, "-"))
512                 fp = stdin;
513         else {
514                 fp = pfctl_fopen(file, "r");
515                 if (fp == NULL)
516                         return (-1);
517         }
518         while ((rv = pfr_next_token(buf, fp)) == 1)
519                 if (append_addr(b, buf, nonetwork)) {
520                         rv = -1;
521                         break;
522                 }
523         if (fp != stdin)
524                 fclose(fp);
525         return (rv);
526 }
527
528 int
529 pfr_next_token(char buf[BUF_SIZE], FILE *fp)
530 {
531         static char     next_ch = ' ';
532         int             i = 0;
533
534         for (;;) {
535                 /* skip spaces */
536                 while (isspace(next_ch) && !feof(fp))
537                         next_ch = fgetc(fp);
538                 /* remove from '#' until end of line */
539                 if (next_ch == '#')
540                         while (!feof(fp)) {
541                                 next_ch = fgetc(fp);
542                                 if (next_ch == '\n')
543                                         break;
544                         }
545                 else
546                         break;
547         }
548         if (feof(fp)) {
549                 next_ch = ' ';
550                 return (0);
551         }
552         do {
553                 if (i < BUF_SIZE)
554                         buf[i++] = next_ch;
555                 next_ch = fgetc(fp);
556         } while (!feof(fp) && !isspace(next_ch));
557         if (i >= BUF_SIZE) {
558                 errno = EINVAL;
559                 return (-1);
560         }
561         buf[i] = '\0';
562         return (1);
563 }
564
565 char *
566 pfr_strerror(int errnum)
567 {
568         switch (errnum) {
569         case ESRCH:
570                 return "Table does not exist";
571         case ENOENT:
572                 return "Anchor or Ruleset does not exist";
573         default:
574                 return strerror(errnum);
575         }
576 }