4 * Copyright (C) 2012 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 #include <netinet/ip.h>
38 #include <arpa/nameser.h>
41 #include "netinet/ipl.h"
44 static const char rcsid[] = "@(#)$Id$";
48 # define IPF_SAVEDIR "/var/db/ipf"
51 # define IPF_NATFILE "ipnat.ipf"
54 # define IPF_STATEFILE "ipstate.ipf"
57 #if !defined(__SVR4) && defined(__GNUC__)
58 extern char *index __P((const char *, int));
64 int main __P((int, char *[]));
65 void usage __P((void));
66 int changestateif __P((char *, char *));
67 int changenatif __P((char *, char *));
68 int readstate __P((int, char *));
69 int readnat __P((int, char *));
70 int writestate __P((int, char *));
71 int opendevice __P((char *));
72 void closedevice __P((int));
73 int setlock __P((int, int));
74 int writeall __P((char *));
75 int readall __P((char *));
76 int writenat __P((int, char *));
84 fprintf(stderr, "usage: %s [-nv] -l\n", progname);
85 fprintf(stderr, "usage: %s [-nv] -u\n", progname);
86 fprintf(stderr, "usage: %s [-nv] [-d <dir>] -R\n", progname);
87 fprintf(stderr, "usage: %s [-nv] [-d <dir>] -W\n", progname);
88 fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -r\n", progname);
89 fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -w\n", progname);
90 fprintf(stderr, "usage: %s [-nNSv] -f <filename> -i <if1>,<if2>\n",
97 * Change interface names in state information saved out to disk.
99 int changestateif(ifs, fname)
102 int fd, olen, nlen, rw;
107 s = strchr(ifs, ',');
113 if (nlen >= sizeof(ips.ips_is.is_ifname) ||
114 olen >= sizeof(ips.ips_is.is_ifname))
117 fd = open(fname, O_RDWR);
123 for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) {
125 if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) {
126 strcpy(ips.ips_is.is_ifname[0], s);
129 if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) {
130 strcpy(ips.ips_is.is_ifname[1], s);
133 if (!strncmp(ips.ips_is.is_ifname[2], ifs, olen + 1)) {
134 strcpy(ips.ips_is.is_ifname[2], s);
137 if (!strncmp(ips.ips_is.is_ifname[3], ifs, olen + 1)) {
138 strcpy(ips.ips_is.is_ifname[3], s);
142 if (lseek(fd, pos, SEEK_SET) != pos) {
146 if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) {
151 pos = lseek(fd, 0, SEEK_CUR);
160 * Change interface names in NAT information saved out to disk.
162 int changenatif(ifs, fname)
165 int fd, olen, nlen, rw;
171 s = strchr(ifs, ',');
178 if (nlen >= sizeof(nat->nat_ifnames[0]) ||
179 olen >= sizeof(nat->nat_ifnames[0]))
182 fd = open(fname, O_RDWR);
188 for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) {
190 if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) {
191 strcpy(nat->nat_ifnames[0], s);
194 if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) {
195 strcpy(nat->nat_ifnames[1], s);
199 if (lseek(fd, pos, SEEK_SET) != pos) {
203 if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) {
208 pos = lseek(fd, 0, SEEK_CUR);
220 int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0;
221 char *dirname = NULL, *filename = NULL, *ifs = NULL;
224 while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1)
228 if ((set == 0) && !dirname && !filename)
234 if ((set != 0) && !dirname && !filename)
244 if (filename || dirname || set)
250 opts |= OPT_DONOTHING;
253 if ((ns >= 0) || dirname || (rw != -1) || set)
259 if (dirname || (rw != -1) || (ns == -1))
269 if ((ns >= 0) || dirname || (rw != -1) || set)
275 if (filename || dirname || set)
284 if (dirname || (rw != -1) || (ns == -1))
299 if (!filename || ns < 0)
302 return changenatif(ifs, filename);
304 return changestateif(ifs, filename);
307 if ((ns >= 0) || (lock >= 0)) {
309 devfd = opendevice(NULL);
312 devfd = opendevice(IPSTATE_NAME);
314 devfd = opendevice(IPNAT_NAME);
321 err = setlock(devfd, lock);
323 if (rw & 1) { /* WRITE */
325 err = writeall(dirname);
328 err = writenat(devfd, filename);
330 err = writestate(devfd, filename);
334 err = readall(dirname);
337 err = readnat(devfd, filename);
339 err = readstate(devfd, filename);
347 int opendevice(ipfdev)
352 if (opts & OPT_DONOTHING)
358 if ((fd = open(ipfdev, O_RDWR)) == -1)
359 if ((fd = open(ipfdev, O_RDONLY)) == -1)
360 perror("open device");
372 int setlock(fd, lock)
375 if (opts & OPT_VERBOSE)
376 printf("Turn lock %s\n", lock ? "on" : "off");
377 if (!(opts & OPT_DONOTHING)) {
378 if (ioctl(fd, SIOCSTLCK, &lock) == -1) {
382 if (opts & OPT_VERBOSE)
383 printf("Lock now %s\n", lock ? "on" : "off");
389 int writestate(fd, file)
393 ipstate_save_t ips, *ipsp;
398 file = IPF_STATEFILE;
400 wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
402 fprintf(stderr, "%s ", file);
403 perror("state:open");
408 bzero((char *)&obj, sizeof(obj));
409 bzero((char *)ipsp, sizeof(ips));
411 obj.ipfo_rev = IPFILTER_VERSION;
412 obj.ipfo_size = sizeof(*ipsp);
413 obj.ipfo_type = IPFOBJ_STATESAVE;
418 if (opts & OPT_VERBOSE)
419 printf("Getting state from addr %p\n", ips.ips_next);
420 if (ioctl(fd, SIOCSTGET, &obj)) {
423 perror("state:SIOCSTGET");
427 if (opts & OPT_VERBOSE)
428 printf("Got state next %p\n", ips.ips_next);
429 if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) {
430 perror("state:write");
434 } while (ips.ips_next != NULL);
441 int readstate(fd, file)
445 ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL;
450 file = IPF_STATEFILE;
452 sfd = open(file, O_RDONLY, 0600);
454 fprintf(stderr, "%s ", file);
459 bzero((char *)&ips, sizeof(ips));
462 * 1. Read all state information in.
465 i = read(sfd, &ips, sizeof(ips));
472 if (i != sizeof(ips)) {
473 fprintf(stderr, "state:incomplete read: %d != %d\n",
474 i, (int)sizeof(ips));
477 is = (ipstate_save_t *)malloc(sizeof(*is));
479 fprintf(stderr, "malloc failed\n");
483 bcopy((char *)&ips, (char *)is, sizeof(ips));
486 * Check to see if this is the first state entry that will
487 * reference a particular rule and if so, flag it as such
488 * else just adjust the rule pointer to become a pointer to
489 * the other. We do this so we have a means later for tracking
490 * who is referencing us when we get back the real pointer
491 * in is_rule after doing the ioctl.
493 for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next)
494 if (is1->ips_rule == is->ips_rule)
497 is->ips_is.is_flags |= SI_NEWFR;
499 is->ips_rule = (void *)&is1->ips_rule;
502 * Use a tail-queue type list (add things to the end)..
508 ipstail->ips_next = is;
514 obj.ipfo_rev = IPFILTER_VERSION;
515 obj.ipfo_size = sizeof(*is);
516 obj.ipfo_type = IPFOBJ_STATESAVE;
518 while ((is = ipshead) != NULL) {
519 if (opts & OPT_VERBOSE)
520 printf("Loading new state table entry\n");
521 if (is->ips_is.is_flags & SI_NEWFR) {
522 if (opts & OPT_VERBOSE)
523 printf("Loading new filter rule\n");
527 if (!(opts & OPT_DONOTHING))
528 if (ioctl(fd, SIOCSTPUT, &obj)) {
533 if (is->ips_is.is_flags & SI_NEWFR) {
534 if (opts & OPT_VERBOSE)
535 printf("Real rule addr %p\n", is->ips_rule);
536 for (is1 = is->ips_next; is1; is1 = is1->ips_next)
537 if (is1->ips_rule == (frentry_t *)&is->ips_rule)
538 is1->ips_rule = is->ips_rule;
541 ipshead = is->ips_next;
548 while ((is = ipshead) != NULL) {
549 ipshead = is->ips_next;
558 int readnat(fd, file)
562 nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL;
577 nfd = open(file, O_RDONLY);
579 fprintf(stderr, "%s ", file);
584 bzero((char *)&ipn, sizeof(ipn));
587 * 1. Read all state information in.
590 i = read(nfd, &ipn, sizeof(ipn));
597 if (i != sizeof(ipn)) {
598 fprintf(stderr, "nat:incomplete read: %d != %d\n",
599 i, (int)sizeof(ipn));
603 in = (nat_save_t *)malloc(ipn.ipn_dsize);
605 fprintf(stderr, "nat:cannot malloc nat save atruct\n");
609 if (ipn.ipn_dsize > sizeof(ipn)) {
610 n = ipn.ipn_dsize - sizeof(ipn);
612 s = in->ipn_data + sizeof(in->ipn_data);
618 "nat:incomplete read: %d != %d\n",
624 bcopy((char *)&ipn, (char *)in, sizeof(ipn));
627 * Check to see if this is the first NAT entry that will
628 * reference a particular rule and if so, flag it as such
629 * else just adjust the rule pointer to become a pointer to
630 * the other. We do this so we have a means later for tracking
631 * who is referencing us when we get back the real pointer
632 * in is_rule after doing the ioctl.
635 if (nat->nat_fr != NULL) {
636 for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next)
637 if (in1->ipn_rule == nat->nat_fr)
640 nat->nat_flags |= SI_NEWFR;
642 nat->nat_fr = &in1->ipn_fr;
646 * Use a tail-queue type list (add things to the end)..
652 ipntail->ipn_next = in;
659 obj.ipfo_rev = IPFILTER_VERSION;
660 obj.ipfo_type = IPFOBJ_NATSAVE;
662 while ((in = ipnhead) != NULL) {
663 if (opts & OPT_VERBOSE)
664 printf("Loading new NAT table entry\n");
666 if (nat->nat_flags & SI_NEWFR) {
667 if (opts & OPT_VERBOSE)
668 printf("Loading new filter rule\n");
672 obj.ipfo_size = in->ipn_dsize;
673 if (!(opts & OPT_DONOTHING))
674 if (ioctl(fd, SIOCSTPUT, &obj)) {
675 fprintf(stderr, "in=%p:", in);
680 if (nat->nat_flags & SI_NEWFR) {
681 if (opts & OPT_VERBOSE)
682 printf("Real rule addr %p\n", nat->nat_fr);
683 for (in1 = in->ipn_next; in1; in1 = in1->ipn_next)
684 if (in1->ipn_rule == &in->ipn_fr)
685 in1->ipn_rule = nat->nat_fr;
688 ipnhead = in->ipn_next;
695 while ((in = ipnhead) != NULL) {
696 ipnhead = in->ipn_next;
705 int writenat(fd, file)
709 nat_save_t *ipnp = NULL, *next = NULL;
717 nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
719 fprintf(stderr, "%s ", file);
724 obj.ipfo_rev = IPFILTER_VERSION;
725 obj.ipfo_type = IPFOBJ_NATSAVE;
728 if (opts & OPT_VERBOSE)
729 printf("Getting nat from addr %p\n", ipnp);
732 if (ioctl(fd, SIOCSTGSZ, &ng)) {
733 perror("nat:SIOCSTGSZ");
740 if (opts & OPT_VERBOSE)
741 printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr);
747 ipnp = malloc(ng.ng_sz);
749 ipnp = realloc((char *)ipnp, ng.ng_sz);
752 "malloc for %d bytes failed\n", ng.ng_sz);
756 bzero((char *)ipnp, ng.ng_sz);
757 obj.ipfo_size = ng.ng_sz;
759 ipnp->ipn_dsize = ng.ng_sz;
760 ipnp->ipn_next = next;
761 if (ioctl(fd, SIOCSTGET, &obj)) {
764 perror("nat:SIOCSTGET");
770 if (opts & OPT_VERBOSE)
771 printf("Got nat next %p ipn_dsize %d ng_sz %d\n",
772 ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz);
773 if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) {
779 next = ipnp->ipn_next;
780 } while (ipnp && next);
789 int writeall(dirname)
795 dirname = IPF_SAVEDIR;
797 if (chdir(dirname)) {
798 fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname);
799 perror("chdir(IPF_SAVEDIR)");
803 fd = opendevice(NULL);
806 if (setlock(fd, 1)) {
811 devfd = opendevice(IPSTATE_NAME);
814 if (writestate(devfd, NULL))
818 devfd = opendevice(IPNAT_NAME);
821 if (writenat(devfd, NULL))
825 if (setlock(fd, 0)) {
846 dirname = IPF_SAVEDIR;
848 if (chdir(dirname)) {
849 perror("chdir(IPF_SAVEDIR)");
853 fd = opendevice(NULL);
856 if (setlock(fd, 1)) {
861 devfd = opendevice(IPSTATE_NAME);
864 if (readstate(devfd, NULL))
868 devfd = opendevice(IPNAT_NAME);
871 if (readnat(devfd, NULL))
875 if (setlock(fd, 0)) {