4 * Copyright (C) 2001-2006 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
9 # ifndef __FreeBSD_cc_version
10 # include <osreldate.h>
12 # if __FreeBSD_cc_version < 430000
13 # include <osreldate.h>
22 #if !defined(__SVR4) && !defined(__GNUC__)
25 #include <sys/types.h>
26 #include <sys/param.h>
30 #include <sys/socket.h>
31 #include <sys/ioctl.h>
32 #include <netinet/in.h>
33 #include <netinet/in_systm.h>
36 #if __FreeBSD_version >= 300000
37 # include <net/if_var.h>
39 #include <netinet/ip.h>
41 #include <arpa/nameser.h>
44 #include "netinet/ipl.h"
47 static const char rcsid[] = "@(#)Id: ipfs.c,v 1.12 2003/12/01 01:56:53 darrenr Exp";
51 # define IPF_SAVEDIR "/var/db/ipf"
54 # define IPF_NATFILE "ipnat.ipf"
57 # define IPF_STATEFILE "ipstate.ipf"
60 #if !defined(__SVR4) && defined(__GNUC__)
61 extern char *index __P((const char *, int));
67 int main __P((int, char *[]));
68 void usage __P((void));
69 int changestateif __P((char *, char *));
70 int changenatif __P((char *, char *));
71 int readstate __P((int, char *));
72 int readnat __P((int, char *));
73 int writestate __P((int, char *));
74 int opendevice __P((char *));
75 void closedevice __P((int));
76 int setlock __P((int, int));
77 int writeall __P((char *));
78 int readall __P((char *));
79 int writenat __P((int, char *));
87 fprintf(stderr, "usage: %s [-nv] -l\n", progname);
88 fprintf(stderr, "usage: %s [-nv] -u\n", progname);
89 fprintf(stderr, "usage: %s [-nv] [-d <dir>] -R\n", progname);
90 fprintf(stderr, "usage: %s [-nv] [-d <dir>] -W\n", progname);
91 fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -r\n", progname);
92 fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -w\n", progname);
93 fprintf(stderr, "usage: %s [-nNSv] -f <filename> -i <if1>,<if2>\n",
100 * Change interface names in state information saved out to disk.
102 int changestateif(ifs, fname)
105 int fd, olen, nlen, rw;
110 s = strchr(ifs, ',');
116 if (nlen >= sizeof(ips.ips_is.is_ifname) ||
117 olen >= sizeof(ips.ips_is.is_ifname))
120 fd = open(fname, O_RDWR);
126 for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) {
128 if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) {
129 strcpy(ips.ips_is.is_ifname[0], s);
132 if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) {
133 strcpy(ips.ips_is.is_ifname[1], s);
136 if (!strncmp(ips.ips_is.is_ifname[2], ifs, olen + 1)) {
137 strcpy(ips.ips_is.is_ifname[2], s);
140 if (!strncmp(ips.ips_is.is_ifname[3], ifs, olen + 1)) {
141 strcpy(ips.ips_is.is_ifname[3], s);
145 if (lseek(fd, pos, SEEK_SET) != pos) {
149 if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) {
154 pos = lseek(fd, 0, SEEK_CUR);
163 * Change interface names in NAT information saved out to disk.
165 int changenatif(ifs, fname)
168 int fd, olen, nlen, rw;
174 s = strchr(ifs, ',');
181 if (nlen >= sizeof(nat->nat_ifnames[0]) ||
182 olen >= sizeof(nat->nat_ifnames[0]))
185 fd = open(fname, O_RDWR);
191 for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) {
193 if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) {
194 strcpy(nat->nat_ifnames[0], s);
197 if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) {
198 strcpy(nat->nat_ifnames[1], s);
201 if (!strncmp(nat->nat_ifnames[2], ifs, olen + 1)) {
202 strcpy(nat->nat_ifnames[2], s);
205 if (!strncmp(nat->nat_ifnames[3], ifs, olen + 1)) {
206 strcpy(nat->nat_ifnames[3], s);
210 if (lseek(fd, pos, SEEK_SET) != pos) {
214 if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) {
219 pos = lseek(fd, 0, SEEK_CUR);
231 int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0;
232 char *dirname = NULL, *filename = NULL, *ifs = NULL;
235 while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1)
239 if ((set == 0) && !dirname && !filename)
245 if ((set != 0) && !dirname && !filename)
255 if (filename || dirname || set)
261 opts |= OPT_DONOTHING;
264 if ((ns >= 0) || dirname || (rw != -1) || set)
270 if (dirname || (rw != -1) || (ns == -1))
280 if ((ns >= 0) || dirname || (rw != -1) || set)
286 if (filename || dirname || set)
295 if (dirname || (rw != -1) || (ns == -1))
310 if (!filename || ns < 0)
313 return changenatif(ifs, filename);
315 return changestateif(ifs, filename);
318 if ((ns >= 0) || (lock >= 0)) {
320 devfd = opendevice(NULL);
323 devfd = opendevice(IPSTATE_NAME);
325 devfd = opendevice(IPNAT_NAME);
332 err = setlock(devfd, lock);
334 if (rw & 1) { /* WRITE */
336 err = writeall(dirname);
339 err = writenat(devfd, filename);
341 err = writestate(devfd, filename);
345 err = readall(dirname);
348 err = readnat(devfd, filename);
350 err = readstate(devfd, filename);
358 int opendevice(ipfdev)
363 if (opts & OPT_DONOTHING)
369 if ((fd = open(ipfdev, O_RDWR)) == -1)
370 if ((fd = open(ipfdev, O_RDONLY)) == -1)
371 perror("open device");
383 int setlock(fd, lock)
386 if (opts & OPT_VERBOSE)
387 printf("Turn lock %s\n", lock ? "on" : "off");
388 if (!(opts & OPT_DONOTHING)) {
389 if (ioctl(fd, SIOCSTLCK, &lock) == -1) {
393 if (opts & OPT_VERBOSE)
394 printf("Lock now %s\n", lock ? "on" : "off");
400 int writestate(fd, file)
404 ipstate_save_t ips, *ipsp;
409 file = IPF_STATEFILE;
411 wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
413 fprintf(stderr, "%s ", file);
414 perror("state:open");
419 bzero((char *)&obj, sizeof(obj));
420 bzero((char *)ipsp, sizeof(ips));
422 obj.ipfo_rev = IPFILTER_VERSION;
423 obj.ipfo_size = sizeof(*ipsp);
424 obj.ipfo_type = IPFOBJ_STATESAVE;
429 if (opts & OPT_VERBOSE)
430 printf("Getting state from addr %p\n", ips.ips_next);
431 if (ioctl(fd, SIOCSTGET, &obj)) {
434 perror("state:SIOCSTGET");
438 if (opts & OPT_VERBOSE)
439 printf("Got state next %p\n", ips.ips_next);
440 if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) {
441 perror("state:write");
445 } while (ips.ips_next != NULL);
452 int readstate(fd, file)
456 ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL;
461 file = IPF_STATEFILE;
463 sfd = open(file, O_RDONLY, 0600);
465 fprintf(stderr, "%s ", file);
470 bzero((char *)&ips, sizeof(ips));
473 * 1. Read all state information in.
476 i = read(sfd, &ips, sizeof(ips));
483 if (i != sizeof(ips)) {
484 fprintf(stderr, "state:incomplete read: %d != %d\n",
485 i, (int)sizeof(ips));
488 is = (ipstate_save_t *)malloc(sizeof(*is));
490 fprintf(stderr, "malloc failed\n");
494 bcopy((char *)&ips, (char *)is, sizeof(ips));
497 * Check to see if this is the first state entry that will
498 * reference a particular rule and if so, flag it as such
499 * else just adjust the rule pointer to become a pointer to
500 * the other. We do this so we have a means later for tracking
501 * who is referencing us when we get back the real pointer
502 * in is_rule after doing the ioctl.
504 for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next)
505 if (is1->ips_rule == is->ips_rule)
508 is->ips_is.is_flags |= SI_NEWFR;
510 is->ips_rule = (void *)&is1->ips_rule;
513 * Use a tail-queue type list (add things to the end)..
519 ipstail->ips_next = is;
525 obj.ipfo_rev = IPFILTER_VERSION;
526 obj.ipfo_size = sizeof(*is);
527 obj.ipfo_type = IPFOBJ_STATESAVE;
529 while ((is = ipshead) != NULL) {
530 if (opts & OPT_VERBOSE)
531 printf("Loading new state table entry\n");
532 if (is->ips_is.is_flags & SI_NEWFR) {
533 if (opts & OPT_VERBOSE)
534 printf("Loading new filter rule\n");
538 if (!(opts & OPT_DONOTHING))
539 if (ioctl(fd, SIOCSTPUT, &obj)) {
544 if (is->ips_is.is_flags & SI_NEWFR) {
545 if (opts & OPT_VERBOSE)
546 printf("Real rule addr %p\n", is->ips_rule);
547 for (is1 = is->ips_next; is1; is1 = is1->ips_next)
548 if (is1->ips_rule == (frentry_t *)&is->ips_rule)
549 is1->ips_rule = is->ips_rule;
552 ipshead = is->ips_next;
559 while ((is = ipshead) != NULL) {
560 ipshead = is->ips_next;
569 int readnat(fd, file)
573 nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL;
588 nfd = open(file, O_RDONLY);
590 fprintf(stderr, "%s ", file);
595 bzero((char *)&ipn, sizeof(ipn));
598 * 1. Read all state information in.
601 i = read(nfd, &ipn, sizeof(ipn));
608 if (i != sizeof(ipn)) {
609 fprintf(stderr, "nat:incomplete read: %d != %d\n",
610 i, (int)sizeof(ipn));
614 in = (nat_save_t *)malloc(ipn.ipn_dsize);
616 fprintf(stderr, "nat:cannot malloc nat save atruct\n");
620 if (ipn.ipn_dsize > sizeof(ipn)) {
621 n = ipn.ipn_dsize - sizeof(ipn);
623 s = in->ipn_data + sizeof(in->ipn_data);
629 "nat:incomplete read: %d != %d\n",
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 |= SI_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 obj.ipfo_rev = IPFILTER_VERSION;
671 obj.ipfo_type = IPFOBJ_NATSAVE;
673 while ((in = ipnhead) != NULL) {
674 if (opts & OPT_VERBOSE)
675 printf("Loading new NAT table entry\n");
677 if (nat->nat_flags & SI_NEWFR) {
678 if (opts & OPT_VERBOSE)
679 printf("Loading new filter rule\n");
683 obj.ipfo_size = in->ipn_dsize;
684 if (!(opts & OPT_DONOTHING))
685 if (ioctl(fd, SIOCSTPUT, &obj)) {
686 fprintf(stderr, "in=%p:", in);
691 if (nat->nat_flags & SI_NEWFR) {
692 if (opts & OPT_VERBOSE)
693 printf("Real rule addr %p\n", nat->nat_fr);
694 for (in1 = in->ipn_next; in1; in1 = in1->ipn_next)
695 if (in1->ipn_rule == &in->ipn_fr)
696 in1->ipn_rule = nat->nat_fr;
699 ipnhead = in->ipn_next;
706 while ((in = ipnhead) != NULL) {
707 ipnhead = in->ipn_next;
716 int writenat(fd, file)
720 nat_save_t *ipnp = NULL, *next = NULL;
728 nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
730 fprintf(stderr, "%s ", file);
735 obj.ipfo_rev = IPFILTER_VERSION;
736 obj.ipfo_type = IPFOBJ_NATSAVE;
739 if (opts & OPT_VERBOSE)
740 printf("Getting nat from addr %p\n", ipnp);
743 if (ioctl(fd, SIOCSTGSZ, &ng)) {
744 perror("nat:SIOCSTGSZ");
751 if (opts & OPT_VERBOSE)
752 printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr);
758 ipnp = malloc(ng.ng_sz);
760 ipnp = realloc((char *)ipnp, ng.ng_sz);
763 "malloc for %d bytes failed\n", ng.ng_sz);
767 bzero((char *)ipnp, ng.ng_sz);
768 obj.ipfo_size = ng.ng_sz;
770 ipnp->ipn_dsize = ng.ng_sz;
771 ipnp->ipn_next = next;
772 if (ioctl(fd, SIOCSTGET, &obj)) {
775 perror("nat:SIOCSTGET");
781 if (opts & OPT_VERBOSE)
782 printf("Got nat next %p ipn_dsize %d ng_sz %d\n",
783 ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz);
784 if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) {
790 next = ipnp->ipn_next;
791 } while (ipnp && next);
800 int writeall(dirname)
806 dirname = IPF_SAVEDIR;
808 if (chdir(dirname)) {
809 fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname);
810 perror("chdir(IPF_SAVEDIR)");
814 fd = opendevice(NULL);
817 if (setlock(fd, 1)) {
822 devfd = opendevice(IPSTATE_NAME);
825 if (writestate(devfd, NULL))
829 devfd = opendevice(IPNAT_NAME);
832 if (writenat(devfd, NULL))
836 if (setlock(fd, 0)) {
857 dirname = IPF_SAVEDIR;
859 if (chdir(dirname)) {
860 perror("chdir(IPF_SAVEDIR)");
864 fd = opendevice(NULL);
867 if (setlock(fd, 1)) {
872 devfd = opendevice(IPSTATE_NAME);
875 if (readstate(devfd, NULL))
879 devfd = opendevice(IPNAT_NAME);
882 if (readnat(devfd, NULL))
886 if (setlock(fd, 0)) {