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