]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sbin/pfctl/pfctl_radix.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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  * 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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 *
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 }