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