File: | src/sbin/pfctl/pfctl_table.c |
Warning: | line 154, column 7 Null pointer passed as 1st argument to string comparison function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: pfctl_table.c,v 1.84 2020/01/15 22:38:31 kn 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/types.h> | |||
34 | #include <sys/ioctl.h> | |||
35 | #include <sys/socket.h> | |||
36 | ||||
37 | #include <netinet/in.h> | |||
38 | #include <arpa/inet.h> | |||
39 | #include <net/if.h> | |||
40 | #include <net/pfvar.h> | |||
41 | ||||
42 | #include <ctype.h> | |||
43 | #include <err.h> | |||
44 | #include <errno(*__errno()).h> | |||
45 | #include <netdb.h> | |||
46 | #include <stdarg.h> | |||
47 | #include <stdio.h> | |||
48 | #include <stdlib.h> | |||
49 | #include <string.h> | |||
50 | #include <time.h> | |||
51 | #include <limits.h> | |||
52 | ||||
53 | #include "pfctl_parser.h" | |||
54 | #include "pfctl.h" | |||
55 | ||||
56 | extern void usage(void); | |||
57 | static void print_table(struct pfr_table *, int, int); | |||
58 | static void print_tstats(struct pfr_tstats *, int); | |||
59 | static int load_addr(struct pfr_buffer *, int, char *[], char *, int, int); | |||
60 | static void print_addrx(struct pfr_addr *, struct pfr_addr *, int); | |||
61 | static void print_astats(struct pfr_astats *, int); | |||
62 | static void xprintf(int, const char *, ...); | |||
63 | static void print_iface(struct pfi_kif *, int); | |||
64 | ||||
65 | static const char *stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = { | |||
66 | { "In/Block:", "In/Match:", "In/Pass:", "In/XPass:" }, | |||
67 | { "Out/Block:", "Out/Match:", "Out/Pass:", "Out/XPass:" } | |||
68 | }; | |||
69 | ||||
70 | static const char *istats_text[2][2][2] = { | |||
71 | { { "In4/Pass:", "In4/Block:" }, { "Out4/Pass:", "Out4/Block:" } }, | |||
72 | { { "In6/Pass:", "In6/Block:" }, { "Out6/Pass:", "Out6/Block:" } } | |||
73 | }; | |||
74 | ||||
75 | #define RVTEST(fct)do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (fct)) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror ((*__errno()))); goto _error; } } while (0) do { \ | |||
76 | if ((!(opts & PF_OPT_NOACTION0x00008) || \ | |||
77 | (opts & PF_OPT_DUMMYACTION0x00100)) && \ | |||
78 | (fct)) { \ | |||
79 | if ((opts & PF_OPT_RECURSE0x04000) == 0) \ | |||
80 | warnx("%s", pf_strerror(errno(*__errno()))); \ | |||
81 | goto _error; \ | |||
82 | } \ | |||
83 | } while (0) | |||
84 | ||||
85 | #define CREATE_TABLEdo { warn_duplicate_tables(table.pfrt_name, table.pfrt_anchor ); table.pfrt_flags |= 0x00000001; if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_add_tables(&table , 1, &nadd, flags)) && ((*__errno()) != 1)) { warnx ("%s", pf_strerror((*__errno()))); goto _error; } if (nadd) { xprintf(opts, "%d table created", nadd); if (opts & 0x00008 ) return (0); } table.pfrt_flags &= ~0x00000001; } while( 0) do { \ | |||
86 | warn_duplicate_tables(table.pfrt_name, \ | |||
87 | table.pfrt_anchor); \ | |||
88 | table.pfrt_flags |= PFR_TFLAG_PERSIST0x00000001; \ | |||
89 | if ((!(opts & PF_OPT_NOACTION0x00008) || \ | |||
90 | (opts & PF_OPT_DUMMYACTION0x00100)) && \ | |||
91 | (pfr_add_tables(&table, 1, &nadd, flags)) && \ | |||
92 | (errno(*__errno()) != EPERM1)) { \ | |||
93 | warnx("%s", pf_strerror(errno(*__errno()))); \ | |||
94 | goto _error; \ | |||
95 | } \ | |||
96 | if (nadd) { \ | |||
97 | xprintf(opts, "%d table created", nadd); \ | |||
98 | if (opts & PF_OPT_NOACTION0x00008) \ | |||
99 | return (0); \ | |||
100 | } \ | |||
101 | table.pfrt_flags &= ~PFR_TFLAG_PERSIST0x00000001; \ | |||
102 | } while(0) | |||
103 | ||||
104 | int | |||
105 | pfctl_clear_tables(const char *anchor, int opts) | |||
106 | { | |||
107 | int rv; | |||
108 | ||||
109 | if ((rv = pfctl_table(0, NULL((void *)0), NULL((void *)0), "-F", NULL((void *)0), anchor, opts)) == -1) { | |||
110 | if ((opts & PF_OPT_IGNFAIL0x10000) == 0) | |||
111 | exit(1); | |||
112 | } | |||
113 | ||||
114 | return (rv); | |||
115 | } | |||
116 | ||||
117 | void | |||
118 | pfctl_show_tables(const char *anchor, int opts) | |||
119 | { | |||
120 | if (pfctl_table(0, NULL((void *)0), NULL((void *)0), "-s", NULL((void *)0), anchor, opts) == -1) | |||
121 | exit(1); | |||
122 | } | |||
123 | ||||
124 | int | |||
125 | pfctl_table(int argc, char *argv[], char *tname, const char *command, | |||
126 | char *file, const char *anchor, int opts) | |||
127 | { | |||
128 | struct pfr_table table; | |||
129 | struct pfr_buffer b, b2; | |||
130 | struct pfr_addr *a, *a2; | |||
131 | int nadd = 0, ndel = 0, nchange = 0, nzero = 0; | |||
132 | int rv = 0, flags = 0, nmatch = 0; | |||
133 | void *p; | |||
134 | ||||
135 | if (command == NULL((void *)0)) | |||
| ||||
136 | usage(); | |||
137 | if (opts & PF_OPT_NOACTION0x00008) | |||
138 | flags |= PFR_FLAG_DUMMY0x00000002; | |||
139 | ||||
140 | bzero(&b, sizeof(b)); | |||
141 | bzero(&b2, sizeof(b2)); | |||
142 | bzero(&table, sizeof(table)); | |||
143 | if (tname != NULL((void *)0)) { | |||
144 | if (strlen(tname) >= PF_TABLE_NAME_SIZE32) | |||
145 | usage(); | |||
146 | if (strlcpy(table.pfrt_name, tname, | |||
147 | sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name)) | |||
148 | errx(1, "pfctl_table: strlcpy"); | |||
149 | } | |||
150 | if (strlcpy(table.pfrt_anchor, anchor, | |||
151 | sizeof(table.pfrt_anchor)) >= sizeof(table.pfrt_anchor)) | |||
152 | errx(1, "pfctl_table: strlcpy"); | |||
153 | ||||
154 | if (!strcmp(command, "-F")) { | |||
| ||||
155 | if (argc || file != NULL((void *)0)) | |||
156 | usage(); | |||
157 | RVTEST(pfr_clr_tables(&table, &ndel, flags))do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_clr_tables(&table, &ndel, flags))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror((*__errno()))); goto _error ; } } while (0); | |||
158 | xprintf(opts, "%d tables deleted", ndel); | |||
159 | } else if (!strcmp(command, "-s")) { | |||
160 | b.pfrb_type = (opts & PF_OPT_VERBOSE20x00080) ? | |||
161 | PFRB_TSTATS : PFRB_TABLES; | |||
162 | if (argc || file != NULL((void *)0)) | |||
163 | usage(); | |||
164 | for (;;) { | |||
165 | pfr_buf_grow(&b, b.pfrb_size); | |||
166 | b.pfrb_size = b.pfrb_msize; | |||
167 | if (opts & PF_OPT_VERBOSE20x00080) | |||
168 | RVTEST(pfr_get_tstats(&table,do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_get_tstats(&table, b.pfrb_caddr, &b.pfrb_size, flags ))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror( (*__errno()))); goto _error; } } while (0) | |||
169 | b.pfrb_caddr, &b.pfrb_size, flags))do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_get_tstats(&table, b.pfrb_caddr, &b.pfrb_size, flags ))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror( (*__errno()))); goto _error; } } while (0); | |||
170 | else | |||
171 | RVTEST(pfr_get_tables(&table,do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_get_tables(&table, b.pfrb_caddr, &b.pfrb_size, flags ))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror( (*__errno()))); goto _error; } } while (0) | |||
172 | b.pfrb_caddr, &b.pfrb_size, flags))do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_get_tables(&table, b.pfrb_caddr, &b.pfrb_size, flags ))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror( (*__errno()))); goto _error; } } while (0); | |||
173 | if (b.pfrb_size <= b.pfrb_msize) | |||
174 | break; | |||
175 | } | |||
176 | ||||
177 | if ((opts & PF_OPT_SHOWALL0x00400) && b.pfrb_size > 0) | |||
178 | pfctl_print_title("TABLES:"); | |||
179 | ||||
180 | PFRB_FOREACH(p, &b)for ((p) = pfr_buf_next((&b), ((void *)0)); (p) != ((void *)0); (p) = pfr_buf_next((&b), (p))) | |||
181 | if (opts & PF_OPT_VERBOSE20x00080) | |||
182 | print_tstats(p, opts & PF_OPT_DEBUG0x00200); | |||
183 | else | |||
184 | print_table(p, opts & PF_OPT_VERBOSE0x00004, | |||
185 | opts & PF_OPT_DEBUG0x00200); | |||
186 | } else if (!strcmp(command, "kill")) { | |||
187 | if (argc || file != NULL((void *)0)) | |||
188 | usage(); | |||
189 | RVTEST(pfr_del_tables(&table, 1, &ndel, flags))do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_del_tables(&table, 1, &ndel, flags))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror((*__errno()))); goto _error; } } while (0); | |||
190 | xprintf(opts, "%d table deleted", ndel); | |||
191 | } else if (!strcmp(command, "flush")) { | |||
192 | if (argc || file != NULL((void *)0)) | |||
193 | usage(); | |||
194 | RVTEST(pfr_clr_addrs(&table, &ndel, flags))do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_clr_addrs(&table, &ndel, flags))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror((*__errno()))); goto _error ; } } while (0); | |||
195 | xprintf(opts, "%d addresses deleted", ndel); | |||
196 | } else if (!strcmp(command, "add")) { | |||
197 | b.pfrb_type = PFRB_ADDRS; | |||
198 | if (load_addr(&b, argc, argv, file, 0, opts)) | |||
199 | goto _error; | |||
200 | CREATE_TABLEdo { warn_duplicate_tables(table.pfrt_name, table.pfrt_anchor ); table.pfrt_flags |= 0x00000001; if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_add_tables(&table , 1, &nadd, flags)) && ((*__errno()) != 1)) { warnx ("%s", pf_strerror((*__errno()))); goto _error; } if (nadd) { xprintf(opts, "%d table created", nadd); if (opts & 0x00008 ) return (0); } table.pfrt_flags &= ~0x00000001; } while( 0); | |||
201 | if (opts & PF_OPT_VERBOSE0x00004) | |||
202 | flags |= PFR_FLAG_FEEDBACK0x00000004; | |||
203 | RVTEST(pfr_add_addrs(&table, b.pfrb_caddr, b.pfrb_size,do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_add_addrs(&table, b.pfrb_caddr, b.pfrb_size, &nadd , flags))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror ((*__errno()))); goto _error; } } while (0) | |||
204 | &nadd, flags))do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_add_addrs(&table, b.pfrb_caddr, b.pfrb_size, &nadd , flags))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror ((*__errno()))); goto _error; } } while (0); | |||
205 | xprintf(opts, "%d/%d addresses added", nadd, b.pfrb_size); | |||
206 | if (opts & PF_OPT_VERBOSE0x00004) | |||
207 | PFRB_FOREACH(a, &b)for ((a) = pfr_buf_next((&b), ((void *)0)); (a) != ((void *)0); (a) = pfr_buf_next((&b), (a))) | |||
208 | if (opts & PF_OPT_VERBOSE20x00080 || | |||
209 | a->pfra_fback != PFR_FB_NONE) | |||
210 | print_addrx(a, NULL((void *)0), | |||
211 | opts & PF_OPT_USEDNS0x00040); | |||
212 | } else if (!strcmp(command, "delete")) { | |||
213 | b.pfrb_type = PFRB_ADDRS; | |||
214 | if (load_addr(&b, argc, argv, file, 0, opts)) | |||
215 | goto _error; | |||
216 | if (opts & PF_OPT_VERBOSE0x00004) | |||
217 | flags |= PFR_FLAG_FEEDBACK0x00000004; | |||
218 | RVTEST(pfr_del_addrs(&table, b.pfrb_caddr, b.pfrb_size,do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_del_addrs(&table, b.pfrb_caddr, b.pfrb_size, &ndel , flags))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror ((*__errno()))); goto _error; } } while (0) | |||
219 | &ndel, flags))do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_del_addrs(&table, b.pfrb_caddr, b.pfrb_size, &ndel , flags))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror ((*__errno()))); goto _error; } } while (0); | |||
220 | xprintf(opts, "%d/%d addresses deleted", ndel, b.pfrb_size); | |||
221 | if (opts & PF_OPT_VERBOSE0x00004) | |||
222 | PFRB_FOREACH(a, &b)for ((a) = pfr_buf_next((&b), ((void *)0)); (a) != ((void *)0); (a) = pfr_buf_next((&b), (a))) | |||
223 | if (opts & PF_OPT_VERBOSE20x00080 || | |||
224 | a->pfra_fback != PFR_FB_NONE) | |||
225 | print_addrx(a, NULL((void *)0), | |||
226 | opts & PF_OPT_USEDNS0x00040); | |||
227 | } else if (!strcmp(command, "replace")) { | |||
228 | b.pfrb_type = PFRB_ADDRS; | |||
229 | if (load_addr(&b, argc, argv, file, 0, opts)) | |||
230 | goto _error; | |||
231 | CREATE_TABLEdo { warn_duplicate_tables(table.pfrt_name, table.pfrt_anchor ); table.pfrt_flags |= 0x00000001; if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_add_tables(&table , 1, &nadd, flags)) && ((*__errno()) != 1)) { warnx ("%s", pf_strerror((*__errno()))); goto _error; } if (nadd) { xprintf(opts, "%d table created", nadd); if (opts & 0x00008 ) return (0); } table.pfrt_flags &= ~0x00000001; } while( 0); | |||
232 | if (opts & PF_OPT_VERBOSE0x00004) | |||
233 | flags |= PFR_FLAG_FEEDBACK0x00000004; | |||
234 | for (;;) { | |||
235 | int sz2 = b.pfrb_msize; | |||
236 | ||||
237 | RVTEST(pfr_set_addrs(&table, b.pfrb_caddr, b.pfrb_size,do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_set_addrs(&table, b.pfrb_caddr, b.pfrb_size, &sz2 , &nadd, &ndel, &nchange, flags))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror((*__errno()))); goto _error ; } } while (0) | |||
238 | &sz2, &nadd, &ndel, &nchange, flags))do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_set_addrs(&table, b.pfrb_caddr, b.pfrb_size, &sz2 , &nadd, &ndel, &nchange, flags))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror((*__errno()))); goto _error ; } } while (0); | |||
239 | if (sz2 <= b.pfrb_msize) { | |||
240 | b.pfrb_size = sz2; | |||
241 | break; | |||
242 | } else | |||
243 | pfr_buf_grow(&b, sz2); | |||
244 | } | |||
245 | if (nadd) | |||
246 | xprintf(opts, "%d addresses added", nadd); | |||
247 | if (ndel) | |||
248 | xprintf(opts, "%d addresses deleted", ndel); | |||
249 | if (nchange) | |||
250 | xprintf(opts, "%d addresses changed", nchange); | |||
251 | if (!nadd && !ndel && !nchange) | |||
252 | xprintf(opts, "no changes"); | |||
253 | if (opts & PF_OPT_VERBOSE0x00004) | |||
254 | PFRB_FOREACH(a, &b)for ((a) = pfr_buf_next((&b), ((void *)0)); (a) != ((void *)0); (a) = pfr_buf_next((&b), (a))) | |||
255 | if (opts & PF_OPT_VERBOSE20x00080 || | |||
256 | a->pfra_fback != PFR_FB_NONE) | |||
257 | print_addrx(a, NULL((void *)0), | |||
258 | opts & PF_OPT_USEDNS0x00040); | |||
259 | } else if (!strcmp(command, "expire")) { | |||
260 | const char *errstr; | |||
261 | u_int lifetime; | |||
262 | ||||
263 | b.pfrb_type = PFRB_ASTATS; | |||
264 | b2.pfrb_type = PFRB_ADDRS; | |||
265 | if (argc != 1 || file != NULL((void *)0)) | |||
266 | usage(); | |||
267 | lifetime = strtonum(*argv, 0, UINT_MAX(2147483647 *2U +1U), &errstr); | |||
268 | if (errstr) | |||
269 | errx(1, "expiry time: %s", errstr); | |||
270 | for (;;) { | |||
271 | pfr_buf_grow(&b, b.pfrb_size); | |||
272 | b.pfrb_size = b.pfrb_msize; | |||
273 | RVTEST(pfr_get_astats(&table, b.pfrb_caddr,do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_get_astats(&table, b.pfrb_caddr, &b.pfrb_size, flags ))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror( (*__errno()))); goto _error; } } while (0) | |||
274 | &b.pfrb_size, flags))do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_get_astats(&table, b.pfrb_caddr, &b.pfrb_size, flags ))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror( (*__errno()))); goto _error; } } while (0); | |||
275 | if (b.pfrb_size <= b.pfrb_msize) | |||
276 | break; | |||
277 | } | |||
278 | PFRB_FOREACH(p, &b)for ((p) = pfr_buf_next((&b), ((void *)0)); (p) != ((void *)0); (p) = pfr_buf_next((&b), (p))) { | |||
279 | ((struct pfr_astats *)p)->pfras_a.pfra_fback = PFR_FB_NONE; | |||
280 | if (time(NULL((void *)0)) - ((struct pfr_astats *)p)->pfras_tzero > | |||
281 | lifetime) | |||
282 | if (pfr_buf_add(&b2, | |||
283 | &((struct pfr_astats *)p)->pfras_a)) | |||
284 | err(1, "duplicate buffer"); | |||
285 | } | |||
286 | ||||
287 | if (opts & PF_OPT_VERBOSE0x00004) | |||
288 | flags |= PFR_FLAG_FEEDBACK0x00000004; | |||
289 | RVTEST(pfr_del_addrs(&table, b2.pfrb_caddr, b2.pfrb_size,do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_del_addrs(&table, b2.pfrb_caddr, b2.pfrb_size, & ndel, flags))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror ((*__errno()))); goto _error; } } while (0) | |||
290 | &ndel, flags))do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_del_addrs(&table, b2.pfrb_caddr, b2.pfrb_size, & ndel, flags))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror ((*__errno()))); goto _error; } } while (0); | |||
291 | xprintf(opts, "%d/%d addresses expired", ndel, b2.pfrb_size); | |||
292 | if (opts & PF_OPT_VERBOSE0x00004) | |||
293 | PFRB_FOREACH(a, &b2)for ((a) = pfr_buf_next((&b2), ((void *)0)); (a) != ((void *)0); (a) = pfr_buf_next((&b2), (a))) | |||
294 | if (opts & PF_OPT_VERBOSE20x00080 || | |||
295 | a->pfra_fback != PFR_FB_NONE) | |||
296 | print_addrx(a, NULL((void *)0), | |||
297 | opts & PF_OPT_USEDNS0x00040); | |||
298 | } else if (!strcmp(command, "show")) { | |||
299 | b.pfrb_type = (opts & PF_OPT_VERBOSE0x00004) ? | |||
300 | PFRB_ASTATS : PFRB_ADDRS; | |||
301 | if (argc || file != NULL((void *)0)) | |||
302 | usage(); | |||
303 | for (;;) { | |||
304 | pfr_buf_grow(&b, b.pfrb_size); | |||
305 | b.pfrb_size = b.pfrb_msize; | |||
306 | if (opts & PF_OPT_VERBOSE0x00004) | |||
307 | RVTEST(pfr_get_astats(&table, b.pfrb_caddr,do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_get_astats(&table, b.pfrb_caddr, &b.pfrb_size, flags ))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror( (*__errno()))); goto _error; } } while (0) | |||
308 | &b.pfrb_size, flags))do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_get_astats(&table, b.pfrb_caddr, &b.pfrb_size, flags ))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror( (*__errno()))); goto _error; } } while (0); | |||
309 | else | |||
310 | RVTEST(pfr_get_addrs(&table, b.pfrb_caddr,do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_get_addrs(&table, b.pfrb_caddr, &b.pfrb_size, flags ))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror( (*__errno()))); goto _error; } } while (0) | |||
311 | &b.pfrb_size, flags))do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_get_addrs(&table, b.pfrb_caddr, &b.pfrb_size, flags ))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror( (*__errno()))); goto _error; } } while (0); | |||
312 | if (b.pfrb_size <= b.pfrb_msize) | |||
313 | break; | |||
314 | } | |||
315 | PFRB_FOREACH(p, &b)for ((p) = pfr_buf_next((&b), ((void *)0)); (p) != ((void *)0); (p) = pfr_buf_next((&b), (p))) | |||
316 | if (opts & PF_OPT_VERBOSE0x00004) | |||
317 | print_astats(p, opts & PF_OPT_USEDNS0x00040); | |||
318 | else | |||
319 | print_addrx(p, NULL((void *)0), opts & PF_OPT_USEDNS0x00040); | |||
320 | } else if (!strcmp(command, "test")) { | |||
321 | b.pfrb_type = PFRB_ADDRS; | |||
322 | b2.pfrb_type = PFRB_ADDRS; | |||
323 | ||||
324 | if (load_addr(&b, argc, argv, file, 1, opts)) | |||
325 | goto _error; | |||
326 | if (opts & PF_OPT_VERBOSE20x00080) { | |||
327 | flags |= PFR_FLAG_REPLACE0x00000020; | |||
328 | PFRB_FOREACH(a, &b)for ((a) = pfr_buf_next((&b), ((void *)0)); (a) != ((void *)0); (a) = pfr_buf_next((&b), (a))) | |||
329 | if (pfr_buf_add(&b2, a)) | |||
330 | err(1, "duplicate buffer"); | |||
331 | } | |||
332 | RVTEST(pfr_tst_addrs(&table, b.pfrb_caddr, b.pfrb_size,do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_tst_addrs(&table, b.pfrb_caddr, b.pfrb_size, &nmatch , flags))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror ((*__errno()))); goto _error; } } while (0) | |||
333 | &nmatch, flags))do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_tst_addrs(&table, b.pfrb_caddr, b.pfrb_size, &nmatch , flags))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror ((*__errno()))); goto _error; } } while (0); | |||
334 | xprintf(opts, "%d/%d addresses match", nmatch, b.pfrb_size); | |||
335 | if ((opts & PF_OPT_VERBOSE0x00004) && !(opts & PF_OPT_VERBOSE20x00080)) | |||
336 | PFRB_FOREACH(a, &b)for ((a) = pfr_buf_next((&b), ((void *)0)); (a) != ((void *)0); (a) = pfr_buf_next((&b), (a))) | |||
337 | if (a->pfra_fback == PFR_FB_MATCH) | |||
338 | print_addrx(a, NULL((void *)0), | |||
339 | opts & PF_OPT_USEDNS0x00040); | |||
340 | if (opts & PF_OPT_VERBOSE20x00080) { | |||
341 | a2 = NULL((void *)0); | |||
342 | PFRB_FOREACH(a, &b)for ((a) = pfr_buf_next((&b), ((void *)0)); (a) != ((void *)0); (a) = pfr_buf_next((&b), (a))) { | |||
343 | a2 = pfr_buf_next(&b2, a2); | |||
344 | print_addrx(a2, a, opts & PF_OPT_USEDNS0x00040); | |||
345 | } | |||
346 | } | |||
347 | if (nmatch < b.pfrb_size) | |||
348 | rv = 2; | |||
349 | } else if (!strcmp(command, "zero")) { | |||
350 | if (argc || file != NULL((void *)0)) | |||
351 | usage(); | |||
352 | flags |= PFR_FLAG_ADDRSTOO0x00000010; | |||
353 | RVTEST(pfr_clr_tstats(&table, 1, &nzero, flags))do { if ((!(opts & 0x00008) || (opts & 0x00100)) && (pfr_clr_tstats(&table, 1, &nzero, flags))) { if ((opts & 0x04000) == 0) warnx("%s", pf_strerror((*__errno()))); goto _error; } } while (0); | |||
354 | xprintf(opts, "%d table/stats cleared", nzero); | |||
355 | } else | |||
356 | warnx("pfctl_table: unknown command '%s'", command); | |||
357 | goto _cleanup; | |||
358 | ||||
359 | _error: | |||
360 | rv = -1; | |||
361 | _cleanup: | |||
362 | pfr_buf_clear(&b); | |||
363 | pfr_buf_clear(&b2); | |||
364 | return (rv); | |||
365 | } | |||
366 | ||||
367 | void | |||
368 | print_table(struct pfr_table *ta, int verbose, int debug) | |||
369 | { | |||
370 | if (!debug && !(ta->pfrt_flags & PFR_TFLAG_ACTIVE0x00000004)) | |||
371 | return; | |||
372 | if (verbose) { | |||
373 | printf("%c%c%c%c%c%c%c\t%s", | |||
374 | (ta->pfrt_flags & PFR_TFLAG_CONST0x00000002) ? 'c' : '-', | |||
375 | (ta->pfrt_flags & PFR_TFLAG_PERSIST0x00000001) ? 'p' : '-', | |||
376 | (ta->pfrt_flags & PFR_TFLAG_ACTIVE0x00000004) ? 'a' : '-', | |||
377 | (ta->pfrt_flags & PFR_TFLAG_INACTIVE0x00000008) ? 'i' : '-', | |||
378 | (ta->pfrt_flags & PFR_TFLAG_REFERENCED0x00000010) ? 'r' : '-', | |||
379 | (ta->pfrt_flags & PFR_TFLAG_REFDANCHOR0x00000020) ? 'h' : '-', | |||
380 | (ta->pfrt_flags & PFR_TFLAG_COUNTERS0x00000040) ? 'C' : '-', | |||
381 | ta->pfrt_name); | |||
382 | if (ta->pfrt_anchor[0]) | |||
383 | printf("\t%s", ta->pfrt_anchor); | |||
384 | puts(""); | |||
385 | } else | |||
386 | puts(ta->pfrt_name); | |||
387 | } | |||
388 | ||||
389 | void | |||
390 | print_tstats(struct pfr_tstats *ts, int debug) | |||
391 | { | |||
392 | time_t time = ts->pfrts_tzero; | |||
393 | int dir, op; | |||
394 | ||||
395 | if (!debug && !(ts->pfrts_flagspfrts_t.pfrt_flags & PFR_TFLAG_ACTIVE0x00000004)) | |||
396 | return; | |||
397 | print_table(&ts->pfrts_t, 1, debug); | |||
398 | printf("\tAddresses: %d\n", ts->pfrts_cnt); | |||
399 | printf("\tCleared: %s", ctime(&time)); | |||
400 | printf("\tReferences: [ Anchors: %-18d Rules: %-18d ]\n", | |||
401 | ts->pfrts_refcnt[PFR_REFCNT_ANCHOR], | |||
402 | ts->pfrts_refcnt[PFR_REFCNT_RULE]); | |||
403 | printf("\tEvaluations: [ NoMatch: %-18llu Match: %-18llu ]\n", | |||
404 | (unsigned long long)ts->pfrts_nomatch, | |||
405 | (unsigned long long)ts->pfrts_match); | |||
406 | for (dir = 0; dir < PFR_DIR_MAX; dir++) | |||
407 | for (op = 0; op < PFR_OP_TABLE_MAX; op++) | |||
408 | printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", | |||
409 | stats_text[dir][op], | |||
410 | (unsigned long long)ts->pfrts_packets[dir][op], | |||
411 | (unsigned long long)ts->pfrts_bytes[dir][op]); | |||
412 | } | |||
413 | ||||
414 | int | |||
415 | load_addr(struct pfr_buffer *b, int argc, char *argv[], char *file, | |||
416 | int nonetwork, int opts) | |||
417 | { | |||
418 | int ev = 0; | |||
419 | while (argc--) | |||
420 | if ((ev = append_addr(b, *argv++, nonetwork, opts)) == -1) { | |||
421 | if (errno(*__errno())) | |||
422 | warn("cannot decode %s", argv[-1]); | |||
423 | return (-1); | |||
424 | } | |||
425 | if (ev == 1) { /* expected further append_addr call */ | |||
426 | warnx("failed to decode %s", argv[-1]); | |||
427 | return (-1); | |||
428 | } | |||
429 | if (pfr_buf_load(b, file, nonetwork, opts)) { | |||
430 | warn("cannot load %s", file); | |||
431 | return (-1); | |||
432 | } | |||
433 | return (0); | |||
434 | } | |||
435 | ||||
436 | void | |||
437 | print_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns) | |||
438 | { | |||
439 | char ch, buf[256] = "{error}"; | |||
440 | char fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ', 'Y', ' ' }; | |||
441 | unsigned int fback, hostnet; | |||
442 | ||||
443 | fback = (rad != NULL((void *)0)) ? rad->pfra_fback : ad->pfra_fback; | |||
444 | ch = (fback < sizeof(fb)/sizeof(*fb)) ? fb[fback] : '?'; | |||
445 | hostnet = (ad->pfra_af == AF_INET624) ? 128 : 32; | |||
446 | inet_ntop(ad->pfra_af, &ad->pfra_u, buf, sizeof(buf)); | |||
447 | printf("%c %c%s", ch, (ad->pfra_not?'!':' '), buf); | |||
448 | if (ad->pfra_net < hostnet) | |||
449 | printf("/%d", ad->pfra_net); | |||
450 | if (rad != NULL((void *)0) && fback != PFR_FB_NONE) { | |||
451 | if (strlcpy(buf, "{error}", sizeof(buf)) >= sizeof(buf)) | |||
452 | errx(1, "print_addrx: strlcpy"); | |||
453 | inet_ntop(rad->pfra_af, &rad->pfra_u, buf, sizeof(buf)); | |||
454 | printf("\t%c%s", (rad->pfra_not?'!':' '), buf); | |||
455 | if (rad->pfra_net < hostnet) | |||
456 | printf("/%d", rad->pfra_net); | |||
457 | } | |||
458 | if (rad != NULL((void *)0) && fback == PFR_FB_NONE) | |||
459 | printf("\t nomatch"); | |||
460 | if (dns && ad->pfra_net == hostnet) { | |||
461 | char host[NI_MAXHOST256]; | |||
462 | struct sockaddr_storage ss; | |||
463 | ||||
464 | strlcpy(host, "?", sizeof(host)); | |||
465 | bzero(&ss, sizeof(ss)); | |||
466 | ss.ss_family = ad->pfra_af; | |||
467 | if (ss.ss_family == AF_INET2) { | |||
468 | struct sockaddr_in *sin = (struct sockaddr_in *)&ss; | |||
469 | ||||
470 | sin->sin_len = sizeof(*sin); | |||
471 | sin->sin_addr = ad->pfra_ip4addrpfra_u._pfra_ip4addr; | |||
472 | } else { | |||
473 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; | |||
474 | ||||
475 | sin6->sin6_len = sizeof(*sin6); | |||
476 | sin6->sin6_addr = ad->pfra_ip6addrpfra_u._pfra_ip6addr; | |||
477 | } | |||
478 | if (getnameinfo((struct sockaddr *)&ss, ss.ss_len, host, | |||
479 | sizeof(host), NULL((void *)0), 0, NI_NAMEREQD8) == 0) | |||
480 | printf("\t(%s)", host); | |||
481 | } | |||
482 | if (ad->pfra_ifname[0] != '\0') | |||
483 | printf("@%s", ad->pfra_ifname); | |||
484 | printf("\n"); | |||
485 | } | |||
486 | ||||
487 | void | |||
488 | print_astats(struct pfr_astats *as, int dns) | |||
489 | { | |||
490 | time_t time = as->pfras_tzero; | |||
491 | int dir, op; | |||
492 | ||||
493 | print_addrx(&as->pfras_a, NULL((void *)0), dns); | |||
494 | printf("\tCleared: %s", ctime(&time)); | |||
495 | if (as->pfras_a.pfra_states) | |||
496 | printf("\tActive States: %d\n", as->pfras_a.pfra_states); | |||
497 | if (as->pfras_a.pfra_type == PFRKE_COST) | |||
498 | printf("\tWeight: %d\n", as->pfras_a.pfra_weight); | |||
499 | if (as->pfras_a.pfra_ifname[0]) | |||
500 | printf("\tInterface: %s\n", as->pfras_a.pfra_ifname); | |||
501 | if (as->pfras_a.pfra_fback == PFR_FB_NOCOUNT) | |||
502 | return; | |||
503 | for (dir = 0; dir < PFR_DIR_MAX; dir++) | |||
504 | for (op = 0; op < PFR_OP_ADDR_MAX; op++) | |||
505 | printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", | |||
506 | stats_text[dir][op], | |||
507 | (unsigned long long)as->pfras_packets[dir][op], | |||
508 | (unsigned long long)as->pfras_bytes[dir][op]); | |||
509 | } | |||
510 | ||||
511 | int | |||
512 | pfctl_define_table(char *name, int flags, int addrs, const char *anchor, | |||
513 | struct pfr_buffer *ab, u_int32_t ticket) | |||
514 | { | |||
515 | struct pfr_table tbl; | |||
516 | ||||
517 | bzero(&tbl, sizeof(tbl)); | |||
518 | if (strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)) >= | |||
519 | sizeof(tbl.pfrt_name) || strlcpy(tbl.pfrt_anchor, anchor, | |||
520 | sizeof(tbl.pfrt_anchor)) >= sizeof(tbl.pfrt_anchor)) | |||
521 | errx(1, "pfctl_define_table: strlcpy"); | |||
522 | tbl.pfrt_flags = flags; | |||
523 | ||||
524 | return pfr_ina_define(&tbl, ab->pfrb_caddr, ab->pfrb_size, NULL((void *)0), | |||
525 | NULL((void *)0), ticket, addrs ? PFR_FLAG_ADDRSTOO0x00000010 : 0); | |||
526 | } | |||
527 | ||||
528 | void | |||
529 | warn_duplicate_tables(const char *tablename, const char *anchorname) | |||
530 | { | |||
531 | struct pfr_buffer b; | |||
532 | struct pfr_table *t; | |||
533 | ||||
534 | bzero(&b, sizeof(b)); | |||
535 | b.pfrb_type = PFRB_TABLES; | |||
536 | for (;;) { | |||
537 | pfr_buf_grow(&b, b.pfrb_size); | |||
538 | b.pfrb_size = b.pfrb_msize; | |||
539 | if (pfr_get_tables(NULL((void *)0), b.pfrb_caddr, | |||
540 | &b.pfrb_size, PFR_FLAG_ALLRSETS0x00000040)) | |||
541 | err(1, "pfr_get_tables"); | |||
542 | if (b.pfrb_size <= b.pfrb_msize) | |||
543 | break; | |||
544 | } | |||
545 | PFRB_FOREACH(t, &b)for ((t) = pfr_buf_next((&b), ((void *)0)); (t) != ((void *)0); (t) = pfr_buf_next((&b), (t))) { | |||
546 | if (!(t->pfrt_flags & PFR_TFLAG_ACTIVE0x00000004)) | |||
547 | continue; | |||
548 | if (!strcmp(anchorname, t->pfrt_anchor)) | |||
549 | continue; | |||
550 | if (!strcmp(tablename, t->pfrt_name)) | |||
551 | warnx("warning: table <%s> already defined" | |||
552 | " in anchor \"%s\"", tablename, | |||
553 | t->pfrt_anchor[0] ? t->pfrt_anchor : "/"); | |||
554 | } | |||
555 | pfr_buf_clear(&b); | |||
556 | } | |||
557 | ||||
558 | void | |||
559 | xprintf(int opts, const char *fmt, ...) | |||
560 | { | |||
561 | va_list args; | |||
562 | ||||
563 | if (opts & PF_OPT_QUIET0x00010) | |||
564 | return; | |||
565 | ||||
566 | va_start(args, fmt)__builtin_va_start(args, fmt); | |||
567 | vfprintf(stderr(&__sF[2]), fmt, args); | |||
568 | va_end(args)__builtin_va_end(args); | |||
569 | ||||
570 | if (opts & PF_OPT_DUMMYACTION0x00100) | |||
571 | fprintf(stderr(&__sF[2]), " (dummy).\n"); | |||
572 | else if (opts & PF_OPT_NOACTION0x00008) | |||
573 | fprintf(stderr(&__sF[2]), " (syntax only).\n"); | |||
574 | else | |||
575 | fprintf(stderr(&__sF[2]), ".\n"); | |||
576 | } | |||
577 | ||||
578 | ||||
579 | /* interface stuff */ | |||
580 | ||||
581 | void | |||
582 | pfctl_show_ifaces(const char *filter, int opts) | |||
583 | { | |||
584 | struct pfr_buffer b; | |||
585 | struct pfi_kif *p; | |||
586 | int i = 0; | |||
587 | ||||
588 | bzero(&b, sizeof(b)); | |||
589 | b.pfrb_type = PFRB_IFACES; | |||
590 | for (;;) { | |||
591 | pfr_buf_grow(&b, b.pfrb_size); | |||
592 | b.pfrb_size = b.pfrb_msize; | |||
593 | if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size)) | |||
594 | errx(1, "%s", pf_strerror(errno(*__errno()))); | |||
595 | if (b.pfrb_size <= b.pfrb_msize) | |||
596 | break; | |||
597 | i++; | |||
598 | } | |||
599 | if (opts & PF_OPT_SHOWALL0x00400) | |||
600 | pfctl_print_title("INTERFACES:"); | |||
601 | PFRB_FOREACH(p, &b)for ((p) = pfr_buf_next((&b), ((void *)0)); (p) != ((void *)0); (p) = pfr_buf_next((&b), (p))) | |||
602 | print_iface(p, opts); | |||
603 | } | |||
604 | ||||
605 | void | |||
606 | print_iface(struct pfi_kif *p, int opts) | |||
607 | { | |||
608 | time_t tzero = p->pfik_tzero; | |||
609 | int i, af, dir, act; | |||
610 | ||||
611 | printf("%s", p->pfik_name); | |||
612 | if (opts & PF_OPT_VERBOSE0x00004) { | |||
613 | if (p->pfik_flags & PFI_IFLAG_SKIP0x0100) | |||
614 | printf(" (skip)"); | |||
615 | } | |||
616 | printf("\n"); | |||
617 | ||||
618 | if (!(opts & PF_OPT_VERBOSE20x00080)) | |||
619 | return; | |||
620 | printf("\tCleared: %s", ctime(&tzero)); | |||
621 | printf("\tReferences: [ States: %-18d Rules: %-18d ]\n", | |||
622 | p->pfik_states, p->pfik_rules); | |||
623 | for (i = 0; i < 8; i++) { | |||
624 | af = (i>>2) & 1; | |||
625 | dir = (i>>1) &1; | |||
626 | act = i & 1; | |||
627 | printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", | |||
628 | istats_text[af][dir][act], | |||
629 | (unsigned long long)p->pfik_packets[af][dir][act], | |||
630 | (unsigned long long)p->pfik_bytes[af][dir][act]); | |||
631 | } | |||
632 | } |