2 * Copyright (C) 1999-2001 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
7 # ifndef __FreeBSD_cc_version
8 # include <osreldate.h>
10 # if __FreeBSD_cc_version < 430000
11 # include <osreldate.h>
20 #if !defined(__SVR4) && !defined(__GNUC__)
23 #include <sys/types.h>
24 #include <sys/param.h>
28 #include <sys/socket.h>
29 #include <sys/ioctl.h>
30 #include <netinet/in.h>
31 #include <netinet/in_systm.h>
34 #if __FreeBSD_version >= 300000
35 # include <net/if_var.h>
37 #include <netinet/ip.h>
39 #include <arpa/nameser.h>
41 #include "ip_compat.h"
48 static const char rcsid[] = "@(#)$Id: ipfs.c,v 2.6.2.15 2003/05/31 02:12:21 darrenr Exp $";
52 # define IPF_SAVEDIR "/var/db/ipf"
55 # define IPF_NATFILE "ipnat.ipf"
58 # define IPF_STATEFILE "ipstate.ipf"
61 #if !defined(__SVR4) && defined(__GNUC__)
62 extern char *index __P((const char *, int));
68 int main __P((int, char *[]));
69 void usage __P((void));
70 int changestateif __P((char *, char *));
71 int changenatif __P((char *, char *));
72 int readstate __P((int, char *));
73 int readnat __P((int, char *));
74 int writestate __P((int, char *));
75 int opendevice __P((char *));
76 void closedevice __P((int));
77 int setlock __P((int, int));
78 int writeall __P((char *));
79 int readall __P((char *));
80 int writenat __P((int, char *));
81 char *concat __P((char *, char *));
92 usage: %s [-nv] [-d <dir>] -R\n\
93 usage: %s [-nv] [-d <dir>] -W\n\
94 usage: %s [-nv] -N [-f <file> | -d <dir>] -r\n\
95 usage: %s [-nv] -S [-f <file> | -d <dir>] -r\n\
96 usage: %s [-nv] -N [-f <file> | -d <dir>] -w\n\
97 usage: %s [-nv] -S [-f <file> | -d <dir>] -w\n\
98 usage: %s [-nv] -N [-f <filename> | -d <dir> ] -i <if1>,<if2>\n\
99 usage: %s [-nv] -S [-f <filename> | -d <dir> ] -i <if1>,<if2>\n\
100 ", progname, progname, progname, progname, progname, progname,
101 progname, progname, progname, progname);
107 * Change interface names in state information saved out to disk.
109 int changestateif(ifs, fname)
112 int fd, olen, nlen, rw;
117 s = strchr(ifs, ',');
123 if (nlen >= sizeof(ips.ips_is.is_ifname) ||
124 olen >= sizeof(ips.ips_is.is_ifname))
127 fd = open(fname, O_RDWR);
133 for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) {
135 if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) {
136 strcpy(ips.ips_is.is_ifname[0], s);
139 if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) {
140 strcpy(ips.ips_is.is_ifname[1], s);
144 if (lseek(fd, pos, SEEK_SET) != pos) {
148 if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) {
153 pos = lseek(fd, 0, SEEK_CUR);
162 * Change interface names in NAT information saved out to disk.
164 int changenatif(ifs, fname)
167 int fd, olen, nlen, rw;
173 s = strchr(ifs, ',');
180 if (nlen >= sizeof(nat->nat_ifname) || olen >= sizeof(nat->nat_ifname))
183 fd = open(fname, O_RDWR);
189 for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) {
191 if (!strncmp(nat->nat_ifname, ifs, olen + 1)) {
192 strcpy(nat->nat_ifname, s);
196 if (lseek(fd, pos, SEEK_SET) != pos) {
200 if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) {
205 pos = lseek(fd, 0, SEEK_CUR);
217 int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0;
218 char *dirname = NULL, *filename = NULL, *ifs = NULL;
222 while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1)
226 if ((set == 0) && !dirname && !filename)
232 if ((set == 1) && !dirname && !filename && !(rw & 2))
242 if (filename || dirname || set)
248 opts |= OPT_DONOTHING;
251 if ((ns >= 0) || dirname || (rw != -1) || set)
257 if (dirname || (rw != -1) || (ns == -1))
263 if (filename || (ns != -1))
269 if ((ns >= 0) || dirname || (rw != -1) || set)
275 if (filename || dirname || set)
284 if (dirname || (rw != -1) || (ns == -1))
290 if (filename || (ns != -1))
303 if (filename == NULL) {
306 dirname = IPF_SAVEDIR;
307 if (dirname[strlen(dirname) - 1] != '/')
308 dirname = concat(dirname, "/");
309 filename = concat(dirname, IPF_NATFILE);
310 } else if (ns == 1) {
312 dirname = IPF_SAVEDIR;
313 if (dirname[strlen(dirname) - 1] != '/')
314 dirname = concat(dirname, "/");
315 filename = concat(dirname, IPF_STATEFILE);
320 if (!filename || ns < 0)
323 return changenatif(ifs, filename);
325 return changestateif(ifs, filename);
328 if ((ns >= 0) || (lock >= 0)) {
330 devfd = opendevice(NULL);
333 devfd = opendevice(IPL_STATE);
335 devfd = opendevice(IPL_NAT);
342 err = setlock(devfd, lock);
344 if (rw & 1) { /* WRITE */
346 err = writeall(dirname);
349 err = writenat(devfd, filename);
351 err = writestate(devfd, filename);
355 err = readall(dirname);
358 err = readnat(devfd, filename);
360 err = readstate(devfd, filename);
368 char *concat(base, append)
373 str = malloc(strlen(base) + strlen(append) + 1);
382 int opendevice(ipfdev)
387 if (opts & OPT_DONOTHING)
393 if ((fd = open(ipfdev, O_RDWR)) == -1)
394 if ((fd = open(ipfdev, O_RDONLY)) == -1)
395 perror("open device");
407 int setlock(fd, lock)
410 if (opts & OPT_VERBOSE)
411 printf("Turn lock %s\n", lock ? "on" : "off");
412 if (!(opts & OPT_DONOTHING)) {
413 if (ioctl(fd, SIOCSTLCK, &lock) == -1) {
417 if (opts & OPT_VERBOSE)
418 printf("Lock now %s\n", lock ? "on" : "off");
424 int writestate(fd, file)
428 ipstate_save_t ips, *ipsp;
432 file = IPF_STATEFILE;
434 wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
436 fprintf(stderr, "%s ", file);
437 perror("state:open");
442 bzero((char *)ipsp, sizeof(ips));
445 if (opts & OPT_VERBOSE)
446 printf("Getting state from addr %p\n", ips.ips_next);
447 if (ioctl(fd, SIOCSTGET, &ipsp)) {
450 perror("state:SIOCSTGET");
454 if (opts & OPT_VERBOSE)
455 printf("Got state next %p\n", ips.ips_next);
456 if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) {
457 perror("state:write");
461 } while (ips.ips_next != NULL);
468 int readstate(fd, file)
472 ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL;
476 file = IPF_STATEFILE;
478 sfd = open(file, O_RDONLY, 0600);
480 fprintf(stderr, "%s ", file);
485 bzero((char *)&ips, sizeof(ips));
488 * 1. Read all state information in.
491 i = read(sfd, &ips, sizeof(ips));
499 if (i != sizeof(ips)) {
500 fprintf(stderr, "incomplete read: %d != %d\n", i,
505 is = (ipstate_save_t *)malloc(sizeof(*is));
507 fprintf(stderr, "malloc failed\n");
511 bcopy((char *)&ips, (char *)is, sizeof(ips));
514 * Check to see if this is the first state entry that will
515 * reference a particular rule and if so, flag it as such
516 * else just adjust the rule pointer to become a pointer to
517 * the other. We do this so we have a means later for tracking
518 * who is referencing us when we get back the real pointer
519 * in is_rule after doing the ioctl.
521 for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next)
522 if (is1->ips_rule == is->ips_rule)
525 is->ips_is.is_flags |= FI_NEWFR;
527 is->ips_rule = (void *)&is1->ips_rule;
530 * Use a tail-queue type list (add things to the end)..
536 ipstail->ips_next = is;
542 for (is = ipshead; is; is = is->ips_next) {
543 if (opts & OPT_VERBOSE)
544 printf("Loading new state table entry\n");
545 if (is->ips_is.is_flags & FI_NEWFR) {
546 if (opts & OPT_VERBOSE)
547 printf("Loading new filter rule\n");
549 if (!(opts & OPT_DONOTHING))
550 if (ioctl(fd, SIOCSTPUT, &is)) {
555 if (is->ips_is.is_flags & FI_NEWFR) {
556 if (opts & OPT_VERBOSE)
557 printf("Real rule addr %p\n", is->ips_rule);
558 for (is1 = is->ips_next; is1; is1 = is1->ips_next)
559 if (is1->ips_rule == (frentry_t *)&is->ips_rule)
560 is1->ips_rule = is->ips_rule;
568 int readnat(fd, file)
572 nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL;
581 nfd = open(file, O_RDONLY);
583 fprintf(stderr, "%s ", file);
588 bzero((char *)&ipn, sizeof(ipn));
591 * 1. Read all state information in.
594 i = read(nfd, &ipn, sizeof(ipn));
602 if (i != sizeof(ipn)) {
603 fprintf(stderr, "incomplete read: %d != %d\n", i,
609 if (ipn.ipn_dsize > 0) {
612 if (n > sizeof(ipn.ipn_data))
613 n -= sizeof(ipn.ipn_data);
616 in = malloc(sizeof(*in) + n);
621 s = in->ipn_data + sizeof(in->ipn_data);
627 "incomplete read: %d != %d\n",
634 in = (nat_save_t *)malloc(sizeof(*in));
635 bcopy((char *)&ipn, (char *)in, sizeof(ipn));
638 * Check to see if this is the first NAT entry that will
639 * reference a particular rule and if so, flag it as such
640 * else just adjust the rule pointer to become a pointer to
641 * the other. We do this so we have a means later for tracking
642 * who is referencing us when we get back the real pointer
643 * in is_rule after doing the ioctl.
646 if (nat->nat_fr != NULL) {
647 for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next)
648 if (in1->ipn_rule == nat->nat_fr)
651 nat->nat_flags |= FI_NEWFR;
653 nat->nat_fr = &in1->ipn_fr;
657 * Use a tail-queue type list (add things to the end)..
663 ipntail->ipn_next = in;
670 for (in = ipnhead; in; in = in->ipn_next) {
671 if (opts & OPT_VERBOSE)
672 printf("Loading new NAT table entry\n");
674 if (nat->nat_flags & FI_NEWFR) {
675 if (opts & OPT_VERBOSE)
676 printf("Loading new filter rule\n");
678 if (!(opts & OPT_DONOTHING))
679 if (ioctl(fd, SIOCSTPUT, &in)) {
684 if (nat->nat_flags & FI_NEWFR) {
685 if (opts & OPT_VERBOSE)
686 printf("Real rule addr %p\n", nat->nat_fr);
687 for (in1 = in->ipn_next; in1; in1 = in1->ipn_next)
688 if (in1->ipn_rule == &in->ipn_fr)
689 in1->ipn_rule = nat->nat_fr;
697 int writenat(fd, file)
701 nat_save_t *ipnp = NULL, *next = NULL;
708 nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
710 fprintf(stderr, "%s ", file);
717 if (opts & OPT_VERBOSE)
718 printf("Getting nat from addr %p\n", ipnp);
721 if (ioctl(fd, SIOCSTGSZ, &ng)) {
722 perror("nat:SIOCSTGSZ");
727 if (opts & OPT_VERBOSE)
728 printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr);
734 ipnp = malloc(ng.ng_sz);
736 ipnp = realloc((char *)ipnp, ng.ng_sz);
739 "malloc for %d bytes failed\n", ng.ng_sz);
743 bzero((char *)ipnp, ng.ng_sz);
744 ipnp->ipn_next = next;
745 if (ioctl(fd, SIOCSTGET, &ipnp)) {
748 perror("nat:SIOCSTGET");
753 if (opts & OPT_VERBOSE)
754 printf("Got nat next %p\n", ipnp->ipn_next);
755 if (write(nfd, ipnp, ng.ng_sz) != ng.ng_sz) {
760 next = ipnp->ipn_next;
761 } while (ipnp && next);
768 int writeall(dirname)
774 dirname = IPF_SAVEDIR;
776 if (chdir(dirname)) {
777 fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname);
778 perror("chdir(IPF_SAVEDIR)");
782 fd = opendevice(NULL);
785 if (setlock(fd, 1)) {
790 devfd = opendevice(IPL_STATE);
793 if (writestate(devfd, NULL))
797 devfd = opendevice(IPL_NAT);
800 if (writenat(devfd, NULL))
804 if (setlock(fd, 0)) {
824 dirname = IPF_SAVEDIR;
826 if (chdir(dirname)) {
827 perror("chdir(IPF_SAVEDIR)");
831 fd = opendevice(NULL);
834 if (setlock(fd, 1)) {
839 devfd = opendevice(IPL_STATE);
842 if (readstate(devfd, NULL))
846 devfd = opendevice(IPL_NAT);
849 if (readnat(devfd, NULL))
853 if (setlock(fd, 0)) {