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