1 /* $NetBSD: npfctl.c,v 1.3 2010/12/18 01:07:26 rmind Exp $ */ 2 3 /*- 4 * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This material is based upon work partially supported by The 8 * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __RCSID("$NetBSD: npfctl.c,v 1.3 2010/12/18 01:07:26 rmind Exp $"); 34 35 #include <sys/ioctl.h> 36 #include <sys/stat.h> 37 #include <sys/types.h> 38 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <err.h> 43 #include <fcntl.h> 44 #include <unistd.h> 45 46 #include "npfctl.h" 47 48 #define NPFCTL_START 1 49 #define NPFCTL_STOP 2 50 #define NPFCTL_RELOAD 3 51 #define NPFCTL_FLUSH 4 52 #define NPFCTL_TABLE 5 53 #define NPFCTL_STATS 6 54 #define NPFCTL_SESSIONS_SAVE 7 55 #define NPFCTL_SESSIONS_LOAD 8 56 57 static struct operations_s { 58 const char * cmd; 59 int action; 60 } operations[] = { 61 /* Start, stop, reload */ 62 { "start", NPFCTL_START }, 63 { "stop", NPFCTL_STOP }, 64 { "reload", NPFCTL_RELOAD }, 65 { "flush", NPFCTL_FLUSH }, 66 /* Table */ 67 { "table", NPFCTL_TABLE }, 68 /* Stats */ 69 { "stats", NPFCTL_STATS }, 70 /* Sessions */ 71 { "sess-save", NPFCTL_SESSIONS_SAVE }, 72 { "sess-load", NPFCTL_SESSIONS_LOAD }, 73 /* --- */ 74 { NULL, 0 } 75 }; 76 77 void * 78 zalloc(size_t sz) 79 { 80 void *p; 81 82 p = malloc(sz); 83 if (p == NULL) { 84 perror("zalloc"); 85 exit(EXIT_FAILURE); 86 } 87 memset(p, 0, sz); 88 return p; 89 } 90 91 char * 92 xstrdup(const char *s) 93 { 94 char *p; 95 96 p = strdup(s); 97 if (p == NULL) { 98 perror("xstrdup"); 99 exit(EXIT_FAILURE); 100 } 101 return p; 102 } 103 104 static void 105 usage(void) 106 { 107 const char *progname = getprogname(); 108 109 fprintf(stderr, 110 "usage:\t%s [ start | stop | reload | flush | stats ]\n", 111 progname); 112 fprintf(stderr, 113 "usage:\t%s [ sess-save | sess-load ]\n", 114 progname); 115 fprintf(stderr, 116 "\t%s table <tid> [ flush ]\n", 117 progname); 118 fprintf(stderr, 119 "\t%s table <tid> { add | rem } <address/mask>\n", 120 progname); 121 122 exit(EXIT_FAILURE); 123 } 124 125 static void 126 npfctl_parsecfg(const char *cfg) 127 { 128 char *buf, *p; 129 FILE *fp; 130 size_t n; 131 int l; 132 133 fp = fopen(cfg, "r"); 134 if (fp == NULL) { 135 err(EXIT_FAILURE, "fopen"); 136 } 137 l = 0; 138 buf = NULL; 139 while (getline(&buf, &n, fp) != -1) { 140 l++; 141 p = strpbrk(buf, "#\n"); 142 if (p != NULL) { 143 *p = '\0'; 144 } 145 if (npf_parseline(buf)) { 146 fprintf(stderr, "invalid syntax at line %d\n", l); 147 exit(EXIT_FAILURE); 148 } 149 } 150 if (buf != NULL) { 151 free(buf); 152 } 153 } 154 155 static int 156 npfctl_print_stats(int fd) 157 { 158 uint64_t *st = malloc(NPF_STATS_SIZE); 159 160 if (ioctl(fd, IOC_NPF_STATS, &st) != 0) { 161 err(EXIT_FAILURE, "ioctl(IOC_NPF_STATS)"); 162 } 163 164 printf("Packets passed:\n\t%"PRIu64" default pass\n\t" 165 "%"PRIu64 " ruleset pass\n\t%"PRIu64" session pass\n\n", 166 st[NPF_STAT_PASS_DEFAULT], st[NPF_STAT_PASS_RULESET], 167 st[NPF_STAT_PASS_SESSION]); 168 169 printf("Packets blocked:\n\t%"PRIu64" default block\n\t" 170 "%"PRIu64 " ruleset block\n\n", st[NPF_STAT_BLOCK_DEFAULT], 171 st[NPF_STAT_BLOCK_RULESET]); 172 173 printf("Session and NAT entries:\n\t%"PRIu64" session allocations\n\t" 174 "%"PRIu64" session destructions\n\t%"PRIu64" NAT entry allocations\n\t" 175 "%"PRIu64" NAT entry destructions\n\n", st[NPF_STAT_SESSION_CREATE], 176 st[NPF_STAT_SESSION_DESTROY], st[NPF_STAT_NAT_CREATE], 177 st[NPF_STAT_NAT_DESTROY]); 178 179 printf("Invalid packet state cases:\n\t%"PRIu64" cases in total\n\t" 180 "%"PRIu64" TCP case I\n\t%"PRIu64" TCP case II\n\t%"PRIu64 181 " TCP case III\n\n", st[NPF_STAT_INVALID_STATE], 182 st[NPF_STAT_INVALID_STATE_TCP1], st[NPF_STAT_INVALID_STATE_TCP2], 183 st[NPF_STAT_INVALID_STATE_TCP3]); 184 185 printf("Packet race cases:\n\t%"PRIu64" NAT association race\n\t" 186 "%"PRIu64" duplicate session race\n", st[NPF_STAT_RACE_NAT], 187 st[NPF_STAT_RACE_SESSION]); 188 189 free(st); 190 return 0; 191 } 192 193 static void 194 npfctl(int action, int argc, char **argv) 195 { 196 int fd, ret, ver, boolval; 197 npf_ioctl_table_t tbl; 198 char *arg; 199 200 #ifndef DEBUG 201 fd = open(NPF_DEV_PATH, O_RDONLY); 202 if (fd == -1) { 203 err(EXIT_FAILURE, "cannot open " NPF_DEV_PATH); 204 } 205 ret = ioctl(fd, IOC_NPF_VERSION, &ver); 206 if (ver != NPF_VERSION) { 207 errx(EXIT_FAILURE, "incompatible npf interface version " 208 "(%d, kernel %d)", NPF_VERSION, ver); 209 } 210 #endif 211 switch (action) { 212 case NPFCTL_START: 213 boolval = true; 214 ret = ioctl(fd, IOC_NPF_SWITCH, &boolval); 215 break; 216 case NPFCTL_STOP: 217 boolval = false; 218 ret = ioctl(fd, IOC_NPF_SWITCH, &boolval); 219 break; 220 case NPFCTL_RELOAD: 221 npfctl_init_data(); 222 #ifdef DEBUG 223 npfctl_parsecfg("npf.conf"); 224 return npfctl_ioctl_send(0); 225 #endif 226 npfctl_parsecfg(argc < 3 ? NPF_CONF_PATH : argv[2]); 227 ret = npfctl_ioctl_send(fd); 228 break; 229 case NPFCTL_FLUSH: 230 /* Pass empty configuration to flush. */ 231 npfctl_init_data(); 232 ret = npfctl_ioctl_send(fd); 233 break; 234 case NPFCTL_TABLE: 235 if (argc < 5) { 236 usage(); 237 } 238 tbl.nct_tid = atoi(argv[2]); 239 if (strcmp(argv[3], "add") == 0) { 240 tbl.nct_action = NPF_IOCTL_TBLENT_ADD; 241 arg = argv[4]; 242 } else if (strcmp(argv[3], "rem") == 0) { 243 tbl.nct_action = NPF_IOCTL_TBLENT_REM; 244 arg = argv[4]; 245 } else { 246 tbl.nct_action = 0; 247 arg = argv[3]; 248 } 249 if (!npfctl_parse_v4mask(arg, 250 &tbl.nct_addr, &tbl.nct_mask)) { 251 errx(EXIT_FAILURE, "invalid CIDR '%s'", arg); 252 } 253 ret = ioctl(fd, IOC_NPF_TABLE, &tbl); 254 break; 255 case NPFCTL_STATS: 256 ret = npfctl_print_stats(fd); 257 break; 258 case NPFCTL_SESSIONS_SAVE: 259 ret = npfctl_ioctl_recvse(fd); 260 break; 261 case NPFCTL_SESSIONS_LOAD: 262 ret = npfctl_ioctl_sendse(fd); 263 break; 264 } 265 if (ret == -1) { 266 err(EXIT_FAILURE, "ioctl"); 267 } 268 close(fd); 269 } 270 271 int 272 main(int argc, char **argv) 273 { 274 char *cmd; 275 int n; 276 277 if (argc < 2) { 278 usage(); 279 } 280 cmd = argv[1]; 281 282 /* Find and call the subroutine */ 283 for (n = 0; operations[n].cmd != NULL; n++) { 284 if (strcmp(cmd, operations[n].cmd) != 0) 285 continue; 286 npfctl(operations[n].action, argc, argv); 287 return 0; 288 } 289 usage(); 290 return 0; 291 } 292