2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2019 Gleb Smirnoff <glebius@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
32 #include <sys/ioctl.h>
45 static const char * const typenames[] = {
46 [PFIL_TYPE_IP4] = "IPv4",
47 [PFIL_TYPE_IP6] = "IPv6",
48 [PFIL_TYPE_ETHERNET] = "Ethernet",
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);
56 static const struct cmd {
58 void (*cmd_func)(int argc, char *argv[]);
60 { "heads", listheads },
61 { "hooks", listhooks },
68 main(int argc __unused, char *argv[] __unused)
76 for (int i = 0; cmds[i].cmd_name != NULL; i++)
77 if (!strncmp(argv[0], cmds[i].cmd_name, strlen(argv[0]))) {
79 errx(1, "ambiguous command: %s", argv[0]);
83 errx(1, "unknown command: %s", argv[0]);
85 dev = open("/dev/" PFILDEV, O_RDWR);
87 err(1, "open(%s)", "/dev/" PFILDEV);
89 (*cmds[cmd].cmd_func)(argc, argv);
97 extern char *__progname;
99 fprintf(stderr, "usage: %s (heads|hooks|link|unlink)\n", __progname);
104 listheads(int argc __unused, char *argv[] __unused)
106 struct pfilioc_list plh;
107 u_int nheads, nhooks, i;
112 if (ioctl(dev, PFILIOC_LISTHEADS, &plh) != 0)
113 err(1, "ioctl(PFILIOC_LISTHEADS)");
116 plh.pio_heads = calloc(plh.pio_nheads, sizeof(struct pfilioc_head));
117 if (plh.pio_heads == NULL)
119 plh.pio_hooks = calloc(plh.pio_nhooks, sizeof(struct pfilioc_hook));
120 if (plh.pio_hooks == NULL)
123 nheads = plh.pio_nheads;
124 nhooks = plh.pio_nhooks;
126 if (ioctl(dev, PFILIOC_LISTHEADS, &plh) != 0)
127 err(1, "ioctl(PFILIOC_LISTHEADS)");
129 if (plh.pio_nheads > nheads || plh.pio_nhooks > nhooks) {
135 #define FMTHD "%16s %8s\n"
136 #define FMTHK "%29s %16s %16s\n"
137 printf(FMTHD, "Intercept point", "Type");
138 for (i = 0, h = 0; i < plh.pio_nheads; i++) {
139 printf(FMTHD, plh.pio_heads[i].pio_name,
140 typenames[plh.pio_heads[i].pio_type]);
141 for (j = 0; j < plh.pio_heads[i].pio_nhooksin; j++, h++)
142 printf(FMTHK, "In", plh.pio_hooks[h].pio_module,
143 plh.pio_hooks[h].pio_ruleset);
144 for (j = 0; j < plh.pio_heads[i].pio_nhooksout; j++, h++)
145 printf(FMTHK, "Out", plh.pio_hooks[h].pio_module,
146 plh.pio_hooks[h].pio_ruleset);
151 listhooks(int argc __unused, char *argv[] __unused)
153 struct pfilioc_list plh;
157 if (ioctl(dev, PFILIOC_LISTHEADS, &plh) != 0)
158 err(1, "ioctl(PFILIOC_LISTHEADS)");
160 plh.pio_hooks = calloc(plh.pio_nhooks, sizeof(struct pfilioc_hook));
161 if (plh.pio_hooks == NULL)
164 nhooks = plh.pio_nhooks;
166 if (ioctl(dev, PFILIOC_LISTHOOKS, &plh) != 0)
167 err(1, "ioctl(PFILIOC_LISTHOOKS)");
169 if (plh.pio_nhooks > nhooks) {
174 printf("Available hooks:\n");
175 for (i = 0; i < plh.pio_nhooks; i++) {
176 printf("\t%s:%s %s\n", plh.pio_hooks[i].pio_module,
177 plh.pio_hooks[i].pio_ruleset,
178 typenames[plh.pio_hooks[i].pio_type]);
183 hook(int argc, char *argv[])
185 struct pfilioc_link req;
189 if (argv[0][0] == 'u')
190 req.pio_flags = PFIL_UNLINK;
194 while ((c = getopt(argc, argv, "ioa")) != -1)
197 req.pio_flags |= PFIL_IN;
200 req.pio_flags |= PFIL_OUT;
203 req.pio_flags |= PFIL_APPEND;
209 if (!PFIL_DIR(req.pio_flags))
218 /* link mod:ruleset head */
219 if ((ruleset = strchr(argv[0], ':')) == NULL)
224 strlcpy(req.pio_name, argv[1], sizeof(req.pio_name));
225 strlcpy(req.pio_module, argv[0], sizeof(req.pio_module));
226 strlcpy(req.pio_ruleset, ruleset, sizeof(req.pio_ruleset));
228 if (ioctl(dev, PFILIOC_LINK, &req) != 0)
229 err(1, "ioctl(PFILIOC_LINK)");