]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/pfilctl/pfilctl.c
Add two missing eventhandler.h headers
[FreeBSD/FreeBSD.git] / sbin / pfilctl / pfilctl.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2019 Gleb Smirnoff <glebius@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/ioctl.h>
33 #include <net/if.h>
34 #include <net/pfil.h>
35
36 #include <err.h>
37 #include <fcntl.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42
43 static int dev;
44
45 static const char * const typenames[] = {
46         [PFIL_TYPE_IP4] = "IPv4",
47         [PFIL_TYPE_IP6] = "IPv6",
48         [PFIL_TYPE_ETHERNET] = "Ethernet",
49 };
50
51 static void listheads(int argc, char *argv[]);
52 static void listhooks(int argc, char *argv[]);
53 static void hook(int argc, char *argv[]);
54 static void help(void);
55
56 static const struct cmd {
57         const char      *cmd_name;
58         void            (*cmd_func)(int argc, char *argv[]);
59 } cmds[] = {
60         { "heads",      listheads },
61         { "hooks",      listhooks },
62         { "link",       hook },
63         { "unlink",     hook },
64         { NULL,         NULL },
65 };
66
67 int
68 main(int argc __unused, char *argv[] __unused)
69 {
70         int cmd = -1;
71
72         if (--argc == 0)
73                 help();
74         argv++;
75
76         for (int i = 0; cmds[i].cmd_name != NULL; i++)
77                 if (!strncmp(argv[0], cmds[i].cmd_name, strlen(argv[0]))) {
78                         if (cmd != -1)
79                                 errx(1, "ambiguous command: %s", argv[0]);
80                         cmd = i;
81                 }
82         if (cmd == -1)
83                 errx(1, "unknown command: %s", argv[0]);
84
85         dev = open("/dev/" PFILDEV, O_RDWR);
86         if (dev == -1)
87                 err(1, "open(%s)", "/dev/" PFILDEV);
88
89         (*cmds[cmd].cmd_func)(argc, argv);
90
91         return (0);
92 }
93
94 static void
95 help(void)
96 {
97
98         fprintf(stderr, "usage: %s (heads|hooks|link|unlink)\n", getprogname());
99         exit(0);
100 }
101
102 static void
103 listheads(int argc __unused, char *argv[] __unused)
104 {
105         struct pfilioc_list plh;
106         u_int nheads, nhooks, i;
107         int j, h;
108
109         plh.pio_nheads = 0;
110         plh.pio_nhooks = 0;
111         if (ioctl(dev, PFILIOC_LISTHEADS, &plh) != 0)
112                 err(1, "ioctl(PFILIOC_LISTHEADS)");
113
114 retry:
115         plh.pio_heads = calloc(plh.pio_nheads, sizeof(struct pfilioc_head));
116         if (plh.pio_heads == NULL)
117                 err(1, "malloc");
118         plh.pio_hooks = calloc(plh.pio_nhooks, sizeof(struct pfilioc_hook));
119         if (plh.pio_hooks == NULL)
120                 err(1, "malloc");
121
122         nheads = plh.pio_nheads;
123         nhooks = plh.pio_nhooks;
124
125         if (ioctl(dev, PFILIOC_LISTHEADS, &plh) != 0)
126                 err(1, "ioctl(PFILIOC_LISTHEADS)");
127
128         if (plh.pio_nheads > nheads || plh.pio_nhooks > nhooks) {
129                 free(plh.pio_heads);
130                 free(plh.pio_hooks);
131                 goto retry;
132         }
133
134 #define FMTHD   "%16s %8s\n"
135 #define FMTHK   "%29s %16s %16s\n"
136         printf(FMTHD, "Intercept point", "Type");
137         for (i = 0, h = 0; i < plh.pio_nheads; i++) {
138                 printf(FMTHD, plh.pio_heads[i].pio_name,
139                     typenames[plh.pio_heads[i].pio_type]);
140                 for (j = 0; j < plh.pio_heads[i].pio_nhooksin; j++, h++)
141                         printf(FMTHK, "In", plh.pio_hooks[h].pio_module,
142                             plh.pio_hooks[h].pio_ruleset);
143                 for (j = 0; j < plh.pio_heads[i].pio_nhooksout; j++, h++)
144                         printf(FMTHK, "Out", plh.pio_hooks[h].pio_module,
145                             plh.pio_hooks[h].pio_ruleset);
146         }
147 }
148
149 static void
150 listhooks(int argc __unused, char *argv[] __unused)
151 {
152         struct pfilioc_list plh;
153         u_int nhooks, i;
154
155         plh.pio_nhooks = 0;
156         if (ioctl(dev, PFILIOC_LISTHEADS, &plh) != 0)
157                 err(1, "ioctl(PFILIOC_LISTHEADS)");
158 retry:
159         plh.pio_hooks = calloc(plh.pio_nhooks, sizeof(struct pfilioc_hook));
160         if (plh.pio_hooks == NULL)
161                 err(1, "malloc");
162
163         nhooks = plh.pio_nhooks;
164
165         if (ioctl(dev, PFILIOC_LISTHOOKS, &plh) != 0)
166                 err(1, "ioctl(PFILIOC_LISTHOOKS)");
167
168         if (plh.pio_nhooks > nhooks) {
169                 free(plh.pio_hooks);
170                 goto retry;
171         }
172
173         printf("Available hooks:\n");
174         for (i = 0; i < plh.pio_nhooks; i++) {
175                 printf("\t%s:%s %s\n", plh.pio_hooks[i].pio_module,
176                     plh.pio_hooks[i].pio_ruleset,
177                     typenames[plh.pio_hooks[i].pio_type]);
178         }
179 }
180
181 static void
182 hook(int argc, char *argv[])
183 {
184         struct pfilioc_link req;
185         int c;
186         char *ruleset;
187
188         if (argv[0][0] == 'u')
189                 req.pio_flags = PFIL_UNLINK;
190         else
191                 req.pio_flags = 0;
192
193         while ((c = getopt(argc, argv, "ioa")) != -1)
194                 switch (c) {
195                 case 'i':
196                         req.pio_flags |= PFIL_IN;
197                         break;
198                 case 'o':
199                         req.pio_flags |= PFIL_OUT;
200                         break;
201                 case 'a':
202                         req.pio_flags |= PFIL_APPEND;
203                         break;
204                 default:
205                         help();
206                 }
207
208         if (!PFIL_DIR(req.pio_flags))
209                 help();
210
211         argc -= optind;
212         argv += optind;
213
214         if (argc != 2)
215                 help();
216
217         /* link mod:ruleset head */
218         if ((ruleset = strchr(argv[0], ':')) == NULL)
219                 help();
220         *ruleset = '\0';
221         ruleset++;
222
223         strlcpy(req.pio_name, argv[1], sizeof(req.pio_name));
224         strlcpy(req.pio_module, argv[0], sizeof(req.pio_module));
225         strlcpy(req.pio_ruleset, ruleset, sizeof(req.pio_ruleset));
226
227         if (ioctl(dev, PFILIOC_LINK, &req) != 0)
228                 err(1, "ioctl(PFILIOC_LINK)");
229 }