| 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 | } |