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