1 1.3 mrg /* $NetBSD: ipfs.c,v 1.3 2018/02/04 08:19:42 mrg Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.2 darrenr * Copyright (C) 2012 by Darren Reed. 5 1.1 christos * 6 1.1 christos * See the IPFILTER.LICENCE file for details on licencing. 7 1.1 christos */ 8 1.1 christos #ifdef __FreeBSD__ 9 1.1 christos # ifndef __FreeBSD_cc_version 10 1.1 christos # include <osreldate.h> 11 1.1 christos # else 12 1.1 christos # if __FreeBSD_cc_version < 430000 13 1.1 christos # include <osreldate.h> 14 1.1 christos # endif 15 1.1 christos # endif 16 1.1 christos #endif 17 1.1 christos #include <stdio.h> 18 1.1 christos #include <unistd.h> 19 1.1 christos #include <string.h> 20 1.1 christos #include <fcntl.h> 21 1.1 christos #include <errno.h> 22 1.1 christos #if !defined(__SVR4) && !defined(__GNUC__) 23 1.1 christos #include <strings.h> 24 1.1 christos #endif 25 1.1 christos #include <sys/types.h> 26 1.1 christos #include <sys/param.h> 27 1.1 christos #include <sys/file.h> 28 1.1 christos #include <stdlib.h> 29 1.1 christos #include <stddef.h> 30 1.1 christos #include <sys/socket.h> 31 1.1 christos #include <sys/ioctl.h> 32 1.1 christos #include <netinet/in.h> 33 1.1 christos #include <netinet/in_systm.h> 34 1.1 christos #include <sys/time.h> 35 1.1 christos #include <net/if.h> 36 1.1 christos #if __FreeBSD_version >= 300000 37 1.1 christos # include <net/if_var.h> 38 1.1 christos #endif 39 1.1 christos #include <netinet/ip.h> 40 1.1 christos #include <netdb.h> 41 1.1 christos #include <arpa/nameser.h> 42 1.1 christos #include <resolv.h> 43 1.1 christos #include "ipf.h" 44 1.1 christos #include "netinet/ipl.h" 45 1.1 christos 46 1.1 christos #if !defined(lint) 47 1.3 mrg static __attribute__((__used__)) const char rcsid[] = "@(#)Id: ipfs.c,v 1.1.1.2 2012/07/22 13:44:53 darrenr Exp $"; 48 1.1 christos #endif 49 1.1 christos 50 1.1 christos #ifndef IPF_SAVEDIR 51 1.1 christos # define IPF_SAVEDIR "/var/db/ipf" 52 1.1 christos #endif 53 1.1 christos #ifndef IPF_NATFILE 54 1.1 christos # define IPF_NATFILE "ipnat.ipf" 55 1.1 christos #endif 56 1.1 christos #ifndef IPF_STATEFILE 57 1.1 christos # define IPF_STATEFILE "ipstate.ipf" 58 1.1 christos #endif 59 1.1 christos 60 1.1 christos #if !defined(__SVR4) && defined(__GNUC__) 61 1.1 christos extern char *index __P((const char *, int)); 62 1.1 christos #endif 63 1.1 christos 64 1.1 christos extern char *optarg; 65 1.1 christos extern int optind; 66 1.1 christos 67 1.1 christos int main __P((int, char *[])); 68 1.1 christos void usage __P((void)); 69 1.1 christos int changestateif __P((char *, char *)); 70 1.1 christos int changenatif __P((char *, char *)); 71 1.1 christos int readstate __P((int, char *)); 72 1.1 christos int readnat __P((int, char *)); 73 1.1 christos int writestate __P((int, char *)); 74 1.1 christos int opendevice __P((char *)); 75 1.1 christos void closedevice __P((int)); 76 1.1 christos int setlock __P((int, int)); 77 1.1 christos int writeall __P((char *)); 78 1.1 christos int readall __P((char *)); 79 1.1 christos int writenat __P((int, char *)); 80 1.1 christos 81 1.1 christos int opts = 0; 82 1.1 christos char *progname; 83 1.1 christos 84 1.1 christos 85 1.1 christos void usage() 86 1.1 christos { 87 1.1 christos fprintf(stderr, "usage: %s [-nv] -l\n", progname); 88 1.1 christos fprintf(stderr, "usage: %s [-nv] -u\n", progname); 89 1.1 christos fprintf(stderr, "usage: %s [-nv] [-d <dir>] -R\n", progname); 90 1.1 christos fprintf(stderr, "usage: %s [-nv] [-d <dir>] -W\n", progname); 91 1.1 christos fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -r\n", progname); 92 1.1 christos fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -w\n", progname); 93 1.1 christos fprintf(stderr, "usage: %s [-nNSv] -f <filename> -i <if1>,<if2>\n", 94 1.1 christos progname); 95 1.1 christos exit(1); 96 1.1 christos } 97 1.1 christos 98 1.1 christos 99 1.1 christos /* 100 1.1 christos * Change interface names in state information saved out to disk. 101 1.1 christos */ 102 1.1 christos int changestateif(ifs, fname) 103 1.1 christos char *ifs, *fname; 104 1.1 christos { 105 1.1 christos int fd, olen, nlen, rw; 106 1.1 christos ipstate_save_t ips; 107 1.1 christos off_t pos; 108 1.1 christos char *s; 109 1.1 christos 110 1.1 christos s = strchr(ifs, ','); 111 1.1 christos if (!s) 112 1.1 christos usage(); 113 1.1 christos *s++ = '\0'; 114 1.1 christos nlen = strlen(s); 115 1.1 christos olen = strlen(ifs); 116 1.1 christos if (nlen >= sizeof(ips.ips_is.is_ifname) || 117 1.1 christos olen >= sizeof(ips.ips_is.is_ifname)) 118 1.1 christos usage(); 119 1.1 christos 120 1.1 christos fd = open(fname, O_RDWR); 121 1.1 christos if (fd == -1) { 122 1.1 christos perror("open"); 123 1.1 christos exit(1); 124 1.1 christos } 125 1.1 christos 126 1.1 christos for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) { 127 1.1 christos rw = 0; 128 1.1 christos if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) { 129 1.1 christos strcpy(ips.ips_is.is_ifname[0], s); 130 1.1 christos rw = 1; 131 1.1 christos } 132 1.1 christos if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) { 133 1.1 christos strcpy(ips.ips_is.is_ifname[1], s); 134 1.1 christos rw = 1; 135 1.1 christos } 136 1.1 christos if (!strncmp(ips.ips_is.is_ifname[2], ifs, olen + 1)) { 137 1.1 christos strcpy(ips.ips_is.is_ifname[2], s); 138 1.1 christos rw = 1; 139 1.1 christos } 140 1.1 christos if (!strncmp(ips.ips_is.is_ifname[3], ifs, olen + 1)) { 141 1.1 christos strcpy(ips.ips_is.is_ifname[3], s); 142 1.1 christos rw = 1; 143 1.1 christos } 144 1.1 christos if (rw == 1) { 145 1.1 christos if (lseek(fd, pos, SEEK_SET) != pos) { 146 1.1 christos perror("lseek"); 147 1.1 christos exit(1); 148 1.1 christos } 149 1.1 christos if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) { 150 1.1 christos perror("write"); 151 1.1 christos exit(1); 152 1.1 christos } 153 1.1 christos } 154 1.1 christos pos = lseek(fd, 0, SEEK_CUR); 155 1.1 christos } 156 1.1 christos close(fd); 157 1.1 christos 158 1.1 christos return 0; 159 1.1 christos } 160 1.1 christos 161 1.1 christos 162 1.1 christos /* 163 1.1 christos * Change interface names in NAT information saved out to disk. 164 1.1 christos */ 165 1.1 christos int changenatif(ifs, fname) 166 1.1 christos char *ifs, *fname; 167 1.1 christos { 168 1.1 christos int fd, olen, nlen, rw; 169 1.1 christos nat_save_t ipn; 170 1.1 christos nat_t *nat; 171 1.1 christos off_t pos; 172 1.1 christos char *s; 173 1.1 christos 174 1.1 christos s = strchr(ifs, ','); 175 1.1 christos if (!s) 176 1.1 christos usage(); 177 1.1 christos *s++ = '\0'; 178 1.1 christos nlen = strlen(s); 179 1.1 christos olen = strlen(ifs); 180 1.1 christos nat = &ipn.ipn_nat; 181 1.1 christos if (nlen >= sizeof(nat->nat_ifnames[0]) || 182 1.1 christos olen >= sizeof(nat->nat_ifnames[0])) 183 1.1 christos usage(); 184 1.1 christos 185 1.1 christos fd = open(fname, O_RDWR); 186 1.1 christos if (fd == -1) { 187 1.1 christos perror("open"); 188 1.1 christos exit(1); 189 1.1 christos } 190 1.1 christos 191 1.1 christos for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) { 192 1.1 christos rw = 0; 193 1.1 christos if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) { 194 1.1 christos strcpy(nat->nat_ifnames[0], s); 195 1.1 christos rw = 1; 196 1.1 christos } 197 1.1 christos if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) { 198 1.1 christos strcpy(nat->nat_ifnames[1], s); 199 1.1 christos rw = 1; 200 1.1 christos } 201 1.1 christos if (rw == 1) { 202 1.1 christos if (lseek(fd, pos, SEEK_SET) != pos) { 203 1.1 christos perror("lseek"); 204 1.1 christos exit(1); 205 1.1 christos } 206 1.1 christos if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) { 207 1.1 christos perror("write"); 208 1.1 christos exit(1); 209 1.1 christos } 210 1.1 christos } 211 1.1 christos pos = lseek(fd, 0, SEEK_CUR); 212 1.1 christos } 213 1.1 christos close(fd); 214 1.1 christos 215 1.1 christos return 0; 216 1.1 christos } 217 1.1 christos 218 1.1 christos 219 1.1 christos int main(argc,argv) 220 1.1 christos int argc; 221 1.1 christos char *argv[]; 222 1.1 christos { 223 1.1 christos int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0; 224 1.1 christos char *dirname = NULL, *filename = NULL, *ifs = NULL; 225 1.1 christos 226 1.1 christos progname = argv[0]; 227 1.1 christos while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1) 228 1.1 christos switch (c) 229 1.1 christos { 230 1.1 christos case 'd' : 231 1.1 christos if ((set == 0) && !dirname && !filename) 232 1.1 christos dirname = optarg; 233 1.1 christos else 234 1.1 christos usage(); 235 1.1 christos break; 236 1.1 christos case 'f' : 237 1.1 christos if ((set != 0) && !dirname && !filename) 238 1.1 christos filename = optarg; 239 1.1 christos else 240 1.1 christos usage(); 241 1.1 christos break; 242 1.1 christos case 'i' : 243 1.1 christos ifs = optarg; 244 1.1 christos set = 1; 245 1.1 christos break; 246 1.1 christos case 'l' : 247 1.1 christos if (filename || dirname || set) 248 1.1 christos usage(); 249 1.1 christos lock = 1; 250 1.1 christos set = 1; 251 1.1 christos break; 252 1.1 christos case 'n' : 253 1.1 christos opts |= OPT_DONOTHING; 254 1.1 christos break; 255 1.1 christos case 'N' : 256 1.1 christos if ((ns >= 0) || dirname || (rw != -1) || set) 257 1.1 christos usage(); 258 1.1 christos ns = 0; 259 1.1 christos set = 1; 260 1.1 christos break; 261 1.1 christos case 'r' : 262 1.1 christos if (dirname || (rw != -1) || (ns == -1)) 263 1.1 christos usage(); 264 1.1 christos rw = 0; 265 1.1 christos set = 1; 266 1.1 christos break; 267 1.1 christos case 'R' : 268 1.1 christos rw = 2; 269 1.1 christos set = 1; 270 1.1 christos break; 271 1.1 christos case 'S' : 272 1.1 christos if ((ns >= 0) || dirname || (rw != -1) || set) 273 1.1 christos usage(); 274 1.1 christos ns = 1; 275 1.1 christos set = 1; 276 1.1 christos break; 277 1.1 christos case 'u' : 278 1.1 christos if (filename || dirname || set) 279 1.1 christos usage(); 280 1.1 christos lock = 0; 281 1.1 christos set = 1; 282 1.1 christos break; 283 1.1 christos case 'v' : 284 1.1 christos opts |= OPT_VERBOSE; 285 1.1 christos break; 286 1.1 christos case 'w' : 287 1.1 christos if (dirname || (rw != -1) || (ns == -1)) 288 1.1 christos usage(); 289 1.1 christos rw = 1; 290 1.1 christos set = 1; 291 1.1 christos break; 292 1.1 christos case 'W' : 293 1.1 christos rw = 3; 294 1.1 christos set = 1; 295 1.1 christos break; 296 1.1 christos case '?' : 297 1.1 christos default : 298 1.1 christos usage(); 299 1.1 christos } 300 1.1 christos 301 1.1 christos if (ifs) { 302 1.1 christos if (!filename || ns < 0) 303 1.1 christos usage(); 304 1.1 christos if (ns == 0) 305 1.1 christos return changenatif(ifs, filename); 306 1.1 christos else 307 1.1 christos return changestateif(ifs, filename); 308 1.1 christos } 309 1.1 christos 310 1.1 christos if ((ns >= 0) || (lock >= 0)) { 311 1.1 christos if (lock >= 0) 312 1.1 christos devfd = opendevice(NULL); 313 1.1 christos else if (ns >= 0) { 314 1.1 christos if (ns == 1) 315 1.1 christos devfd = opendevice(IPSTATE_NAME); 316 1.1 christos else if (ns == 0) 317 1.1 christos devfd = opendevice(IPNAT_NAME); 318 1.1 christos } 319 1.1 christos if (devfd == -1) 320 1.1 christos exit(1); 321 1.1 christos } 322 1.1 christos 323 1.1 christos if (lock >= 0) 324 1.1 christos err = setlock(devfd, lock); 325 1.1 christos else if (rw >= 0) { 326 1.1 christos if (rw & 1) { /* WRITE */ 327 1.1 christos if (rw & 2) 328 1.1 christos err = writeall(dirname); 329 1.1 christos else { 330 1.1 christos if (ns == 0) 331 1.1 christos err = writenat(devfd, filename); 332 1.1 christos else if (ns == 1) 333 1.1 christos err = writestate(devfd, filename); 334 1.1 christos } 335 1.1 christos } else { 336 1.1 christos if (rw & 2) 337 1.1 christos err = readall(dirname); 338 1.1 christos else { 339 1.1 christos if (ns == 0) 340 1.1 christos err = readnat(devfd, filename); 341 1.1 christos else if (ns == 1) 342 1.1 christos err = readstate(devfd, filename); 343 1.1 christos } 344 1.1 christos } 345 1.1 christos } 346 1.1 christos return err; 347 1.1 christos } 348 1.1 christos 349 1.1 christos 350 1.1 christos int opendevice(ipfdev) 351 1.1 christos char *ipfdev; 352 1.1 christos { 353 1.1 christos int fd = -1; 354 1.1 christos 355 1.1 christos if (opts & OPT_DONOTHING) 356 1.1 christos return -2; 357 1.1 christos 358 1.1 christos if (!ipfdev) 359 1.1 christos ipfdev = IPL_NAME; 360 1.1 christos 361 1.1 christos if ((fd = open(ipfdev, O_RDWR)) == -1) 362 1.1 christos if ((fd = open(ipfdev, O_RDONLY)) == -1) 363 1.1 christos perror("open device"); 364 1.1 christos return fd; 365 1.1 christos } 366 1.1 christos 367 1.1 christos 368 1.1 christos void closedevice(fd) 369 1.1 christos int fd; 370 1.1 christos { 371 1.1 christos close(fd); 372 1.1 christos } 373 1.1 christos 374 1.1 christos 375 1.1 christos int setlock(fd, lock) 376 1.1 christos int fd, lock; 377 1.1 christos { 378 1.1 christos if (opts & OPT_VERBOSE) 379 1.1 christos printf("Turn lock %s\n", lock ? "on" : "off"); 380 1.1 christos if (!(opts & OPT_DONOTHING)) { 381 1.1 christos if (ioctl(fd, SIOCSTLCK, &lock) == -1) { 382 1.1 christos perror("SIOCSTLCK"); 383 1.1 christos return 1; 384 1.1 christos } 385 1.1 christos if (opts & OPT_VERBOSE) 386 1.1 christos printf("Lock now %s\n", lock ? "on" : "off"); 387 1.1 christos } 388 1.1 christos return 0; 389 1.1 christos } 390 1.1 christos 391 1.1 christos 392 1.1 christos int writestate(fd, file) 393 1.1 christos int fd; 394 1.1 christos char *file; 395 1.1 christos { 396 1.1 christos ipstate_save_t ips, *ipsp; 397 1.1 christos ipfobj_t obj; 398 1.1 christos int wfd = -1; 399 1.1 christos 400 1.1 christos if (!file) 401 1.1 christos file = IPF_STATEFILE; 402 1.1 christos 403 1.1 christos wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); 404 1.1 christos if (wfd == -1) { 405 1.1 christos fprintf(stderr, "%s ", file); 406 1.1 christos perror("state:open"); 407 1.1 christos return 1; 408 1.1 christos } 409 1.1 christos 410 1.1 christos ipsp = &ips; 411 1.1 christos bzero((char *)&obj, sizeof(obj)); 412 1.1 christos bzero((char *)ipsp, sizeof(ips)); 413 1.1 christos 414 1.1 christos obj.ipfo_rev = IPFILTER_VERSION; 415 1.1 christos obj.ipfo_size = sizeof(*ipsp); 416 1.1 christos obj.ipfo_type = IPFOBJ_STATESAVE; 417 1.1 christos obj.ipfo_ptr = ipsp; 418 1.1 christos 419 1.1 christos do { 420 1.1 christos 421 1.1 christos if (opts & OPT_VERBOSE) 422 1.1 christos printf("Getting state from addr %p\n", ips.ips_next); 423 1.1 christos if (ioctl(fd, SIOCSTGET, &obj)) { 424 1.1 christos if (errno == ENOENT) 425 1.1 christos break; 426 1.1 christos perror("state:SIOCSTGET"); 427 1.1 christos close(wfd); 428 1.1 christos return 1; 429 1.1 christos } 430 1.1 christos if (opts & OPT_VERBOSE) 431 1.1 christos printf("Got state next %p\n", ips.ips_next); 432 1.1 christos if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) { 433 1.1 christos perror("state:write"); 434 1.1 christos close(wfd); 435 1.1 christos return 1; 436 1.1 christos } 437 1.1 christos } while (ips.ips_next != NULL); 438 1.1 christos close(wfd); 439 1.1 christos 440 1.1 christos return 0; 441 1.1 christos } 442 1.1 christos 443 1.1 christos 444 1.1 christos int readstate(fd, file) 445 1.1 christos int fd; 446 1.1 christos char *file; 447 1.1 christos { 448 1.1 christos ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL; 449 1.1 christos int sfd = -1, i; 450 1.1 christos ipfobj_t obj; 451 1.1 christos 452 1.1 christos if (!file) 453 1.1 christos file = IPF_STATEFILE; 454 1.1 christos 455 1.1 christos sfd = open(file, O_RDONLY, 0600); 456 1.1 christos if (sfd == -1) { 457 1.1 christos fprintf(stderr, "%s ", file); 458 1.1 christos perror("open"); 459 1.1 christos return 1; 460 1.1 christos } 461 1.1 christos 462 1.1 christos bzero((char *)&ips, sizeof(ips)); 463 1.1 christos 464 1.1 christos /* 465 1.1 christos * 1. Read all state information in. 466 1.1 christos */ 467 1.1 christos do { 468 1.1 christos i = read(sfd, &ips, sizeof(ips)); 469 1.1 christos if (i == -1) { 470 1.1 christos perror("read"); 471 1.1 christos goto freeipshead; 472 1.1 christos } 473 1.1 christos if (i == 0) 474 1.1 christos break; 475 1.1 christos if (i != sizeof(ips)) { 476 1.1 christos fprintf(stderr, "state:incomplete read: %d != %d\n", 477 1.1 christos i, (int)sizeof(ips)); 478 1.1 christos goto freeipshead; 479 1.1 christos } 480 1.1 christos is = (ipstate_save_t *)malloc(sizeof(*is)); 481 1.1 christos if (is == NULL) { 482 1.1 christos fprintf(stderr, "malloc failed\n"); 483 1.1 christos goto freeipshead; 484 1.1 christos } 485 1.1 christos 486 1.1 christos bcopy((char *)&ips, (char *)is, sizeof(ips)); 487 1.1 christos 488 1.1 christos /* 489 1.1 christos * Check to see if this is the first state entry that will 490 1.1 christos * reference a particular rule and if so, flag it as such 491 1.1 christos * else just adjust the rule pointer to become a pointer to 492 1.1 christos * the other. We do this so we have a means later for tracking 493 1.1 christos * who is referencing us when we get back the real pointer 494 1.1 christos * in is_rule after doing the ioctl. 495 1.1 christos */ 496 1.1 christos for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next) 497 1.1 christos if (is1->ips_rule == is->ips_rule) 498 1.1 christos break; 499 1.1 christos if (is1 == NULL) 500 1.1 christos is->ips_is.is_flags |= SI_NEWFR; 501 1.1 christos else 502 1.1 christos is->ips_rule = (void *)&is1->ips_rule; 503 1.1 christos 504 1.1 christos /* 505 1.1 christos * Use a tail-queue type list (add things to the end).. 506 1.1 christos */ 507 1.1 christos is->ips_next = NULL; 508 1.1 christos if (!ipshead) 509 1.1 christos ipshead = is; 510 1.1 christos if (ipstail) 511 1.1 christos ipstail->ips_next = is; 512 1.1 christos ipstail = is; 513 1.1 christos } while (1); 514 1.1 christos 515 1.1 christos close(sfd); 516 1.1 christos 517 1.1 christos obj.ipfo_rev = IPFILTER_VERSION; 518 1.1 christos obj.ipfo_size = sizeof(*is); 519 1.1 christos obj.ipfo_type = IPFOBJ_STATESAVE; 520 1.1 christos 521 1.1 christos while ((is = ipshead) != NULL) { 522 1.1 christos if (opts & OPT_VERBOSE) 523 1.1 christos printf("Loading new state table entry\n"); 524 1.1 christos if (is->ips_is.is_flags & SI_NEWFR) { 525 1.1 christos if (opts & OPT_VERBOSE) 526 1.1 christos printf("Loading new filter rule\n"); 527 1.1 christos } 528 1.1 christos 529 1.1 christos obj.ipfo_ptr = is; 530 1.1 christos if (!(opts & OPT_DONOTHING)) 531 1.1 christos if (ioctl(fd, SIOCSTPUT, &obj)) { 532 1.1 christos perror("SIOCSTPUT"); 533 1.1 christos goto freeipshead; 534 1.1 christos } 535 1.1 christos 536 1.1 christos if (is->ips_is.is_flags & SI_NEWFR) { 537 1.1 christos if (opts & OPT_VERBOSE) 538 1.1 christos printf("Real rule addr %p\n", is->ips_rule); 539 1.1 christos for (is1 = is->ips_next; is1; is1 = is1->ips_next) 540 1.1 christos if (is1->ips_rule == (frentry_t *)&is->ips_rule) 541 1.1 christos is1->ips_rule = is->ips_rule; 542 1.1 christos } 543 1.1 christos 544 1.1 christos ipshead = is->ips_next; 545 1.1 christos free(is); 546 1.1 christos } 547 1.1 christos 548 1.1 christos return 0; 549 1.1 christos 550 1.1 christos freeipshead: 551 1.1 christos while ((is = ipshead) != NULL) { 552 1.1 christos ipshead = is->ips_next; 553 1.1 christos free(is); 554 1.1 christos } 555 1.1 christos if (sfd != -1) 556 1.1 christos close(sfd); 557 1.1 christos return 1; 558 1.1 christos } 559 1.1 christos 560 1.1 christos 561 1.1 christos int readnat(fd, file) 562 1.1 christos int fd; 563 1.1 christos char *file; 564 1.1 christos { 565 1.1 christos nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL; 566 1.1 christos ipfobj_t obj; 567 1.1 christos int nfd, i; 568 1.1 christos nat_t *nat; 569 1.1 christos char *s; 570 1.1 christos int n; 571 1.1 christos 572 1.1 christos nfd = -1; 573 1.1 christos in = NULL; 574 1.1 christos ipnhead = NULL; 575 1.1 christos ipntail = NULL; 576 1.1 christos 577 1.1 christos if (!file) 578 1.1 christos file = IPF_NATFILE; 579 1.1 christos 580 1.1 christos nfd = open(file, O_RDONLY); 581 1.1 christos if (nfd == -1) { 582 1.1 christos fprintf(stderr, "%s ", file); 583 1.1 christos perror("nat:open"); 584 1.1 christos return 1; 585 1.1 christos } 586 1.1 christos 587 1.1 christos bzero((char *)&ipn, sizeof(ipn)); 588 1.1 christos 589 1.1 christos /* 590 1.1 christos * 1. Read all state information in. 591 1.1 christos */ 592 1.1 christos do { 593 1.1 christos i = read(nfd, &ipn, sizeof(ipn)); 594 1.1 christos if (i == -1) { 595 1.1 christos perror("read"); 596 1.1 christos goto freenathead; 597 1.1 christos } 598 1.1 christos if (i == 0) 599 1.1 christos break; 600 1.1 christos if (i != sizeof(ipn)) { 601 1.1 christos fprintf(stderr, "nat:incomplete read: %d != %d\n", 602 1.1 christos i, (int)sizeof(ipn)); 603 1.1 christos goto freenathead; 604 1.1 christos } 605 1.1 christos 606 1.1 christos in = (nat_save_t *)malloc(ipn.ipn_dsize); 607 1.1 christos if (in == NULL) { 608 1.1 christos fprintf(stderr, "nat:cannot malloc nat save atruct\n"); 609 1.1 christos goto freenathead; 610 1.1 christos } 611 1.1 christos 612 1.1 christos if (ipn.ipn_dsize > sizeof(ipn)) { 613 1.1 christos n = ipn.ipn_dsize - sizeof(ipn); 614 1.1 christos if (n > 0) { 615 1.1 christos s = in->ipn_data + sizeof(in->ipn_data); 616 1.1 christos i = read(nfd, s, n); 617 1.1 christos if (i == 0) 618 1.1 christos break; 619 1.1 christos if (i != n) { 620 1.1 christos fprintf(stderr, 621 1.1 christos "nat:incomplete read: %d != %d\n", 622 1.1 christos i, n); 623 1.1 christos goto freenathead; 624 1.1 christos } 625 1.1 christos } 626 1.1 christos } 627 1.1 christos bcopy((char *)&ipn, (char *)in, sizeof(ipn)); 628 1.1 christos 629 1.1 christos /* 630 1.1 christos * Check to see if this is the first NAT entry that will 631 1.1 christos * reference a particular rule and if so, flag it as such 632 1.1 christos * else just adjust the rule pointer to become a pointer to 633 1.1 christos * the other. We do this so we have a means later for tracking 634 1.1 christos * who is referencing us when we get back the real pointer 635 1.1 christos * in is_rule after doing the ioctl. 636 1.1 christos */ 637 1.1 christos nat = &in->ipn_nat; 638 1.1 christos if (nat->nat_fr != NULL) { 639 1.1 christos for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next) 640 1.1 christos if (in1->ipn_rule == nat->nat_fr) 641 1.1 christos break; 642 1.1 christos if (in1 == NULL) 643 1.1 christos nat->nat_flags |= SI_NEWFR; 644 1.1 christos else 645 1.1 christos nat->nat_fr = &in1->ipn_fr; 646 1.1 christos } 647 1.1 christos 648 1.1 christos /* 649 1.1 christos * Use a tail-queue type list (add things to the end).. 650 1.1 christos */ 651 1.1 christos in->ipn_next = NULL; 652 1.1 christos if (!ipnhead) 653 1.1 christos ipnhead = in; 654 1.1 christos if (ipntail) 655 1.1 christos ipntail->ipn_next = in; 656 1.1 christos ipntail = in; 657 1.1 christos } while (1); 658 1.1 christos 659 1.1 christos close(nfd); 660 1.1 christos nfd = -1; 661 1.1 christos 662 1.1 christos obj.ipfo_rev = IPFILTER_VERSION; 663 1.1 christos obj.ipfo_type = IPFOBJ_NATSAVE; 664 1.1 christos 665 1.1 christos while ((in = ipnhead) != NULL) { 666 1.1 christos if (opts & OPT_VERBOSE) 667 1.1 christos printf("Loading new NAT table entry\n"); 668 1.1 christos nat = &in->ipn_nat; 669 1.1 christos if (nat->nat_flags & SI_NEWFR) { 670 1.1 christos if (opts & OPT_VERBOSE) 671 1.1 christos printf("Loading new filter rule\n"); 672 1.1 christos } 673 1.1 christos 674 1.1 christos obj.ipfo_ptr = in; 675 1.1 christos obj.ipfo_size = in->ipn_dsize; 676 1.1 christos if (!(opts & OPT_DONOTHING)) 677 1.1 christos if (ioctl(fd, SIOCSTPUT, &obj)) { 678 1.1 christos fprintf(stderr, "in=%p:", in); 679 1.1 christos perror("SIOCSTPUT"); 680 1.1 christos return 1; 681 1.1 christos } 682 1.1 christos 683 1.1 christos if (nat->nat_flags & SI_NEWFR) { 684 1.1 christos if (opts & OPT_VERBOSE) 685 1.1 christos printf("Real rule addr %p\n", nat->nat_fr); 686 1.1 christos for (in1 = in->ipn_next; in1; in1 = in1->ipn_next) 687 1.1 christos if (in1->ipn_rule == &in->ipn_fr) 688 1.1 christos in1->ipn_rule = nat->nat_fr; 689 1.1 christos } 690 1.1 christos 691 1.1 christos ipnhead = in->ipn_next; 692 1.1 christos free(in); 693 1.1 christos } 694 1.1 christos 695 1.1 christos return 0; 696 1.1 christos 697 1.1 christos freenathead: 698 1.1 christos while ((in = ipnhead) != NULL) { 699 1.1 christos ipnhead = in->ipn_next; 700 1.1 christos free(in); 701 1.1 christos } 702 1.1 christos if (nfd != -1) 703 1.1 christos close(nfd); 704 1.1 christos return 1; 705 1.1 christos } 706 1.1 christos 707 1.1 christos 708 1.1 christos int writenat(fd, file) 709 1.1 christos int fd; 710 1.1 christos char *file; 711 1.1 christos { 712 1.1 christos nat_save_t *ipnp = NULL, *next = NULL; 713 1.1 christos ipfobj_t obj; 714 1.1 christos int nfd = -1; 715 1.1 christos natget_t ng; 716 1.1 christos 717 1.1 christos if (!file) 718 1.1 christos file = IPF_NATFILE; 719 1.1 christos 720 1.1 christos nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); 721 1.1 christos if (nfd == -1) { 722 1.1 christos fprintf(stderr, "%s ", file); 723 1.1 christos perror("nat:open"); 724 1.1 christos return 1; 725 1.1 christos } 726 1.1 christos 727 1.1 christos obj.ipfo_rev = IPFILTER_VERSION; 728 1.1 christos obj.ipfo_type = IPFOBJ_NATSAVE; 729 1.1 christos 730 1.1 christos do { 731 1.1 christos if (opts & OPT_VERBOSE) 732 1.1 christos printf("Getting nat from addr %p\n", ipnp); 733 1.1 christos ng.ng_ptr = next; 734 1.1 christos ng.ng_sz = 0; 735 1.1 christos if (ioctl(fd, SIOCSTGSZ, &ng)) { 736 1.1 christos perror("nat:SIOCSTGSZ"); 737 1.1 christos close(nfd); 738 1.1 christos if (ipnp != NULL) 739 1.1 christos free(ipnp); 740 1.1 christos return 1; 741 1.1 christos } 742 1.1 christos 743 1.1 christos if (opts & OPT_VERBOSE) 744 1.1 christos printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr); 745 1.1 christos 746 1.1 christos if (ng.ng_sz == 0) 747 1.1 christos break; 748 1.1 christos 749 1.1 christos if (!ipnp) 750 1.1 christos ipnp = malloc(ng.ng_sz); 751 1.1 christos else 752 1.1 christos ipnp = realloc((char *)ipnp, ng.ng_sz); 753 1.1 christos if (!ipnp) { 754 1.1 christos fprintf(stderr, 755 1.1 christos "malloc for %d bytes failed\n", ng.ng_sz); 756 1.1 christos break; 757 1.1 christos } 758 1.1 christos 759 1.1 christos bzero((char *)ipnp, ng.ng_sz); 760 1.1 christos obj.ipfo_size = ng.ng_sz; 761 1.1 christos obj.ipfo_ptr = ipnp; 762 1.1 christos ipnp->ipn_dsize = ng.ng_sz; 763 1.1 christos ipnp->ipn_next = next; 764 1.1 christos if (ioctl(fd, SIOCSTGET, &obj)) { 765 1.1 christos if (errno == ENOENT) 766 1.1 christos break; 767 1.1 christos perror("nat:SIOCSTGET"); 768 1.1 christos close(nfd); 769 1.1 christos free(ipnp); 770 1.1 christos return 1; 771 1.1 christos } 772 1.1 christos 773 1.1 christos if (opts & OPT_VERBOSE) 774 1.1 christos printf("Got nat next %p ipn_dsize %d ng_sz %d\n", 775 1.1 christos ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz); 776 1.1 christos if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) { 777 1.1 christos perror("nat:write"); 778 1.1 christos close(nfd); 779 1.1 christos free(ipnp); 780 1.1 christos return 1; 781 1.1 christos } 782 1.1 christos next = ipnp->ipn_next; 783 1.1 christos } while (ipnp && next); 784 1.1 christos if (ipnp != NULL) 785 1.1 christos free(ipnp); 786 1.1 christos close(nfd); 787 1.1 christos 788 1.1 christos return 0; 789 1.1 christos } 790 1.1 christos 791 1.1 christos 792 1.1 christos int writeall(dirname) 793 1.1 christos char *dirname; 794 1.1 christos { 795 1.1 christos int fd, devfd; 796 1.1 christos 797 1.1 christos if (!dirname) 798 1.1 christos dirname = IPF_SAVEDIR; 799 1.1 christos 800 1.1 christos if (chdir(dirname)) { 801 1.1 christos fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname); 802 1.1 christos perror("chdir(IPF_SAVEDIR)"); 803 1.1 christos return 1; 804 1.1 christos } 805 1.1 christos 806 1.1 christos fd = opendevice(NULL); 807 1.1 christos if (fd == -1) 808 1.1 christos return 1; 809 1.1 christos if (setlock(fd, 1)) { 810 1.1 christos close(fd); 811 1.1 christos return 1; 812 1.1 christos } 813 1.1 christos 814 1.1 christos devfd = opendevice(IPSTATE_NAME); 815 1.1 christos if (devfd == -1) 816 1.1 christos goto bad; 817 1.1 christos if (writestate(devfd, NULL)) 818 1.1 christos goto bad; 819 1.1 christos close(devfd); 820 1.1 christos 821 1.1 christos devfd = opendevice(IPNAT_NAME); 822 1.1 christos if (devfd == -1) 823 1.1 christos goto bad; 824 1.1 christos if (writenat(devfd, NULL)) 825 1.1 christos goto bad; 826 1.1 christos close(devfd); 827 1.1 christos 828 1.1 christos if (setlock(fd, 0)) { 829 1.1 christos close(fd); 830 1.1 christos return 1; 831 1.1 christos } 832 1.1 christos 833 1.1 christos close(fd); 834 1.1 christos return 0; 835 1.1 christos 836 1.1 christos bad: 837 1.1 christos setlock(fd, 0); 838 1.1 christos close(fd); 839 1.1 christos return 1; 840 1.1 christos } 841 1.1 christos 842 1.1 christos 843 1.1 christos int readall(dirname) 844 1.1 christos char *dirname; 845 1.1 christos { 846 1.1 christos int fd, devfd; 847 1.1 christos 848 1.1 christos if (!dirname) 849 1.1 christos dirname = IPF_SAVEDIR; 850 1.1 christos 851 1.1 christos if (chdir(dirname)) { 852 1.1 christos perror("chdir(IPF_SAVEDIR)"); 853 1.1 christos return 1; 854 1.1 christos } 855 1.1 christos 856 1.1 christos fd = opendevice(NULL); 857 1.1 christos if (fd == -1) 858 1.1 christos return 1; 859 1.1 christos if (setlock(fd, 1)) { 860 1.1 christos close(fd); 861 1.1 christos return 1; 862 1.1 christos } 863 1.1 christos 864 1.1 christos devfd = opendevice(IPSTATE_NAME); 865 1.1 christos if (devfd == -1) 866 1.1 christos return 1; 867 1.1 christos if (readstate(devfd, NULL)) 868 1.1 christos return 1; 869 1.1 christos close(devfd); 870 1.1 christos 871 1.1 christos devfd = opendevice(IPNAT_NAME); 872 1.1 christos if (devfd == -1) 873 1.1 christos return 1; 874 1.1 christos if (readnat(devfd, NULL)) 875 1.1 christos return 1; 876 1.1 christos close(devfd); 877 1.1 christos 878 1.1 christos if (setlock(fd, 0)) { 879 1.1 christos close(fd); 880 1.1 christos return 1; 881 1.1 christos } 882 1.1 christos 883 1.1 christos return 0; 884 1.1 christos } 885