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