4 * Copyright (C) 2012 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
13 #if !defined(__SVR4) && !defined(__GNUC__)
16 #include <sys/types.h>
17 #include <sys/param.h>
21 #include <sys/socket.h>
22 #include <sys/ioctl.h>
23 #include <netinet/in.h>
24 #include <netinet/in_systm.h>
27 #include <netinet/ip.h>
29 #include <arpa/nameser.h>
32 #include "netinet/ipl.h"
35 static const char rcsid[] = "@(#)$Id$";
39 # define IPF_SAVEDIR "/var/db/ipf"
42 # define IPF_NATFILE "ipnat.ipf"
45 # define IPF_STATEFILE "ipstate.ipf"
48 #if !defined(__SVR4) && defined(__GNUC__)
49 extern char *index __P((const char *, int));
55 int main __P((int, char *[]));
56 void usage __P((void));
57 int changestateif __P((char *, char *));
58 int changenatif __P((char *, char *));
59 int readstate __P((int, char *));
60 int readnat __P((int, char *));
61 int writestate __P((int, char *));
62 int opendevice __P((char *));
63 void closedevice __P((int));
64 int setlock __P((int, int));
65 int writeall __P((char *));
66 int readall __P((char *));
67 int writenat __P((int, char *));
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",
88 * Change interface names in state information saved out to disk.
90 int changestateif(ifs, fname)
93 int fd, olen, nlen, rw;
104 if (nlen >= sizeof(ips.ips_is.is_ifname) ||
105 olen >= sizeof(ips.ips_is.is_ifname))
108 fd = open(fname, O_RDWR);
114 for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) {
116 if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) {
117 strcpy(ips.ips_is.is_ifname[0], s);
120 if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) {
121 strcpy(ips.ips_is.is_ifname[1], s);
124 if (!strncmp(ips.ips_is.is_ifname[2], ifs, olen + 1)) {
125 strcpy(ips.ips_is.is_ifname[2], s);
128 if (!strncmp(ips.ips_is.is_ifname[3], ifs, olen + 1)) {
129 strcpy(ips.ips_is.is_ifname[3], s);
133 if (lseek(fd, pos, SEEK_SET) != pos) {
137 if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) {
142 pos = lseek(fd, 0, SEEK_CUR);
151 * Change interface names in NAT information saved out to disk.
153 int changenatif(ifs, fname)
156 int fd, olen, nlen, rw;
162 s = strchr(ifs, ',');
169 if (nlen >= sizeof(nat->nat_ifnames[0]) ||
170 olen >= sizeof(nat->nat_ifnames[0]))
173 fd = open(fname, O_RDWR);
179 for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) {
181 if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) {
182 strcpy(nat->nat_ifnames[0], s);
185 if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) {
186 strcpy(nat->nat_ifnames[1], s);
190 if (lseek(fd, pos, SEEK_SET) != pos) {
194 if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) {
199 pos = lseek(fd, 0, SEEK_CUR);
211 int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0;
212 char *dirname = NULL, *filename = NULL, *ifs = NULL;
215 while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1)
219 if ((set == 0) && !dirname && !filename)
225 if ((set != 0) && !dirname && !filename)
235 if (filename || dirname || set)
241 opts |= OPT_DONOTHING;
244 if ((ns >= 0) || dirname || (rw != -1) || set)
250 if (dirname || (rw != -1) || (ns == -1))
260 if ((ns >= 0) || dirname || (rw != -1) || set)
266 if (filename || dirname || set)
275 if (dirname || (rw != -1) || (ns == -1))
290 if (!filename || ns < 0)
293 return changenatif(ifs, filename);
295 return changestateif(ifs, filename);
298 if ((ns >= 0) || (lock >= 0)) {
300 devfd = opendevice(NULL);
303 devfd = opendevice(IPSTATE_NAME);
305 devfd = opendevice(IPNAT_NAME);
312 err = setlock(devfd, lock);
314 if (rw & 1) { /* WRITE */
316 err = writeall(dirname);
319 err = writenat(devfd, filename);
321 err = writestate(devfd, filename);
325 err = readall(dirname);
328 err = readnat(devfd, filename);
330 err = readstate(devfd, filename);
338 int opendevice(ipfdev)
343 if (opts & OPT_DONOTHING)
349 if ((fd = open(ipfdev, O_RDWR)) == -1)
350 if ((fd = open(ipfdev, O_RDONLY)) == -1)
351 perror("open device");
363 int setlock(fd, lock)
366 if (opts & OPT_VERBOSE)
367 printf("Turn lock %s\n", lock ? "on" : "off");
368 if (!(opts & OPT_DONOTHING)) {
369 if (ioctl(fd, SIOCSTLCK, &lock) == -1) {
373 if (opts & OPT_VERBOSE)
374 printf("Lock now %s\n", lock ? "on" : "off");
380 int writestate(fd, file)
384 ipstate_save_t ips, *ipsp;
389 file = IPF_STATEFILE;
391 wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
393 fprintf(stderr, "%s ", file);
394 perror("state:open");
399 bzero((char *)&obj, sizeof(obj));
400 bzero((char *)ipsp, sizeof(ips));
402 obj.ipfo_rev = IPFILTER_VERSION;
403 obj.ipfo_size = sizeof(*ipsp);
404 obj.ipfo_type = IPFOBJ_STATESAVE;
409 if (opts & OPT_VERBOSE)
410 printf("Getting state from addr %p\n", ips.ips_next);
411 if (ioctl(fd, SIOCSTGET, &obj)) {
414 perror("state:SIOCSTGET");
418 if (opts & OPT_VERBOSE)
419 printf("Got state next %p\n", ips.ips_next);
420 if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) {
421 perror("state:write");
425 } while (ips.ips_next != NULL);
432 int readstate(fd, file)
436 ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL;
441 file = IPF_STATEFILE;
443 sfd = open(file, O_RDONLY, 0600);
445 fprintf(stderr, "%s ", file);
450 bzero((char *)&ips, sizeof(ips));
453 * 1. Read all state information in.
456 i = read(sfd, &ips, sizeof(ips));
463 if (i != sizeof(ips)) {
464 fprintf(stderr, "state:incomplete read: %d != %d\n",
465 i, (int)sizeof(ips));
468 is = (ipstate_save_t *)malloc(sizeof(*is));
470 fprintf(stderr, "malloc failed\n");
474 bcopy((char *)&ips, (char *)is, sizeof(ips));
477 * Check to see if this is the first state entry that will
478 * reference a particular rule and if so, flag it as such
479 * else just adjust the rule pointer to become a pointer to
480 * the other. We do this so we have a means later for tracking
481 * who is referencing us when we get back the real pointer
482 * in is_rule after doing the ioctl.
484 for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next)
485 if (is1->ips_rule == is->ips_rule)
488 is->ips_is.is_flags |= SI_NEWFR;
490 is->ips_rule = (void *)&is1->ips_rule;
493 * Use a tail-queue type list (add things to the end)..
499 ipstail->ips_next = is;
505 obj.ipfo_rev = IPFILTER_VERSION;
506 obj.ipfo_size = sizeof(*is);
507 obj.ipfo_type = IPFOBJ_STATESAVE;
509 while ((is = ipshead) != NULL) {
510 if (opts & OPT_VERBOSE)
511 printf("Loading new state table entry\n");
512 if (is->ips_is.is_flags & SI_NEWFR) {
513 if (opts & OPT_VERBOSE)
514 printf("Loading new filter rule\n");
518 if (!(opts & OPT_DONOTHING))
519 if (ioctl(fd, SIOCSTPUT, &obj)) {
524 if (is->ips_is.is_flags & SI_NEWFR) {
525 if (opts & OPT_VERBOSE)
526 printf("Real rule addr %p\n", is->ips_rule);
527 for (is1 = is->ips_next; is1; is1 = is1->ips_next)
528 if (is1->ips_rule == (frentry_t *)&is->ips_rule)
529 is1->ips_rule = is->ips_rule;
532 ipshead = is->ips_next;
539 while ((is = ipshead) != NULL) {
540 ipshead = is->ips_next;
549 int readnat(fd, file)
553 nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL;
568 nfd = open(file, O_RDONLY);
570 fprintf(stderr, "%s ", file);
575 bzero((char *)&ipn, sizeof(ipn));
578 * 1. Read all state information in.
581 i = read(nfd, &ipn, sizeof(ipn));
588 if (i != sizeof(ipn)) {
589 fprintf(stderr, "nat:incomplete read: %d != %d\n",
590 i, (int)sizeof(ipn));
594 in = (nat_save_t *)malloc(ipn.ipn_dsize);
596 fprintf(stderr, "nat:cannot malloc nat save atruct\n");
600 if (ipn.ipn_dsize > sizeof(ipn)) {
601 n = ipn.ipn_dsize - sizeof(ipn);
603 s = in->ipn_data + sizeof(in->ipn_data);
609 "nat:incomplete read: %d != %d\n",
615 bcopy((char *)&ipn, (char *)in, sizeof(ipn));
618 * Check to see if this is the first NAT entry that will
619 * reference a particular rule and if so, flag it as such
620 * else just adjust the rule pointer to become a pointer to
621 * the other. We do this so we have a means later for tracking
622 * who is referencing us when we get back the real pointer
623 * in is_rule after doing the ioctl.
626 if (nat->nat_fr != NULL) {
627 for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next)
628 if (in1->ipn_rule == nat->nat_fr)
631 nat->nat_flags |= SI_NEWFR;
633 nat->nat_fr = &in1->ipn_fr;
637 * Use a tail-queue type list (add things to the end)..
643 ipntail->ipn_next = in;
650 obj.ipfo_rev = IPFILTER_VERSION;
651 obj.ipfo_type = IPFOBJ_NATSAVE;
653 while ((in = ipnhead) != NULL) {
654 if (opts & OPT_VERBOSE)
655 printf("Loading new NAT table entry\n");
657 if (nat->nat_flags & SI_NEWFR) {
658 if (opts & OPT_VERBOSE)
659 printf("Loading new filter rule\n");
663 obj.ipfo_size = in->ipn_dsize;
664 if (!(opts & OPT_DONOTHING))
665 if (ioctl(fd, SIOCSTPUT, &obj)) {
666 fprintf(stderr, "in=%p:", in);
671 if (nat->nat_flags & SI_NEWFR) {
672 if (opts & OPT_VERBOSE)
673 printf("Real rule addr %p\n", nat->nat_fr);
674 for (in1 = in->ipn_next; in1; in1 = in1->ipn_next)
675 if (in1->ipn_rule == &in->ipn_fr)
676 in1->ipn_rule = nat->nat_fr;
679 ipnhead = in->ipn_next;
686 while ((in = ipnhead) != NULL) {
687 ipnhead = in->ipn_next;
696 int writenat(fd, file)
700 nat_save_t *ipnp = NULL, *next = NULL;
708 nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
710 fprintf(stderr, "%s ", file);
715 obj.ipfo_rev = IPFILTER_VERSION;
716 obj.ipfo_type = IPFOBJ_NATSAVE;
719 if (opts & OPT_VERBOSE)
720 printf("Getting nat from addr %p\n", ipnp);
723 if (ioctl(fd, SIOCSTGSZ, &ng)) {
724 perror("nat:SIOCSTGSZ");
731 if (opts & OPT_VERBOSE)
732 printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr);
738 ipnp = malloc(ng.ng_sz);
740 ipnp = realloc((char *)ipnp, ng.ng_sz);
743 "malloc for %d bytes failed\n", ng.ng_sz);
747 bzero((char *)ipnp, ng.ng_sz);
748 obj.ipfo_size = ng.ng_sz;
750 ipnp->ipn_dsize = ng.ng_sz;
751 ipnp->ipn_next = next;
752 if (ioctl(fd, SIOCSTGET, &obj)) {
755 perror("nat:SIOCSTGET");
761 if (opts & OPT_VERBOSE)
762 printf("Got nat next %p ipn_dsize %d ng_sz %d\n",
763 ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz);
764 if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) {
770 next = ipnp->ipn_next;
771 } while (ipnp && next);
780 int writeall(dirname)
786 dirname = IPF_SAVEDIR;
788 if (chdir(dirname)) {
789 fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname);
790 perror("chdir(IPF_SAVEDIR)");
794 fd = opendevice(NULL);
797 if (setlock(fd, 1)) {
802 devfd = opendevice(IPSTATE_NAME);
805 if (writestate(devfd, NULL))
809 devfd = opendevice(IPNAT_NAME);
812 if (writenat(devfd, NULL))
816 if (setlock(fd, 0)) {
837 dirname = IPF_SAVEDIR;
839 if (chdir(dirname)) {
840 perror("chdir(IPF_SAVEDIR)");
844 fd = opendevice(NULL);
847 if (setlock(fd, 1)) {
852 devfd = opendevice(IPSTATE_NAME);
855 if (readstate(devfd, NULL))
859 devfd = opendevice(IPNAT_NAME);
862 if (readnat(devfd, NULL))
866 if (setlock(fd, 0)) {