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(const char *, int);
55 int main(int, char *[]);
57 int changestateif(char *, char *);
58 int changenatif(char *, char *);
59 int readstate(int, char *);
60 int readnat(int, char *);
61 int writestate(int, char *);
62 int opendevice(char *);
63 void closedevice(int);
64 int setlock(int, int);
67 int writenat(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(char *ifs, char *fname)
92 int fd, olen, nlen, rw;
103 if (nlen >= sizeof(ips.ips_is.is_ifname) ||
104 olen >= sizeof(ips.ips_is.is_ifname))
107 fd = open(fname, O_RDWR);
113 for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) {
115 if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) {
116 strcpy(ips.ips_is.is_ifname[0], s);
119 if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) {
120 strcpy(ips.ips_is.is_ifname[1], s);
123 if (!strncmp(ips.ips_is.is_ifname[2], ifs, olen + 1)) {
124 strcpy(ips.ips_is.is_ifname[2], s);
127 if (!strncmp(ips.ips_is.is_ifname[3], ifs, olen + 1)) {
128 strcpy(ips.ips_is.is_ifname[3], s);
132 if (lseek(fd, pos, SEEK_SET) != pos) {
136 if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) {
141 pos = lseek(fd, 0, SEEK_CUR);
150 * Change interface names in NAT information saved out to disk.
152 int changenatif(char *ifs, char *fname)
154 int fd, olen, nlen, rw;
160 s = strchr(ifs, ',');
167 if (nlen >= sizeof(nat->nat_ifnames[0]) ||
168 olen >= sizeof(nat->nat_ifnames[0]))
171 fd = open(fname, O_RDWR);
177 for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) {
179 if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) {
180 strcpy(nat->nat_ifnames[0], s);
183 if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) {
184 strcpy(nat->nat_ifnames[1], s);
188 if (lseek(fd, pos, SEEK_SET) != pos) {
192 if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) {
197 pos = lseek(fd, 0, SEEK_CUR);
205 int main(int argc, char *argv[])
207 int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0;
208 char *dirname = NULL, *filename = NULL, *ifs = NULL;
211 while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1)
215 if ((set == 0) && !dirname && !filename)
221 if ((set != 0) && !dirname && !filename)
231 if (filename || dirname || set)
237 opts |= OPT_DONOTHING;
240 if ((ns >= 0) || dirname || (rw != -1) || set)
246 if (dirname || (rw != -1) || (ns == -1))
256 if ((ns >= 0) || dirname || (rw != -1) || set)
262 if (filename || dirname || set)
271 if (dirname || (rw != -1) || (ns == -1))
286 if (!filename || ns < 0)
289 return (changenatif(ifs, filename));
291 return (changestateif(ifs, filename));
294 if ((ns >= 0) || (lock >= 0)) {
296 devfd = opendevice(NULL);
299 devfd = opendevice(IPSTATE_NAME);
301 devfd = opendevice(IPNAT_NAME);
308 err = setlock(devfd, lock);
310 if (rw & 1) { /* WRITE */
312 err = writeall(dirname);
315 err = writenat(devfd, filename);
317 err = writestate(devfd, filename);
321 err = readall(dirname);
324 err = readnat(devfd, filename);
326 err = readstate(devfd, filename);
334 int opendevice(char *ipfdev)
338 if (opts & OPT_DONOTHING)
344 if ((fd = open(ipfdev, O_RDWR)) == -1)
345 if ((fd = open(ipfdev, O_RDONLY)) == -1)
346 perror("open device");
351 void closedevice(int fd)
357 int setlock(int fd, int lock)
359 if (opts & OPT_VERBOSE)
360 printf("Turn lock %s\n", lock ? "on" : "off");
361 if (!(opts & OPT_DONOTHING)) {
362 if (ioctl(fd, SIOCSTLCK, &lock) == -1) {
366 if (opts & OPT_VERBOSE)
367 printf("Lock now %s\n", lock ? "on" : "off");
373 int writestate(int fd, char *file)
375 ipstate_save_t ips, *ipsp;
380 file = IPF_STATEFILE;
382 wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
384 fprintf(stderr, "%s ", file);
385 perror("state:open");
390 bzero((char *)&obj, sizeof(obj));
391 bzero((char *)ipsp, sizeof(ips));
393 obj.ipfo_rev = IPFILTER_VERSION;
394 obj.ipfo_size = sizeof(*ipsp);
395 obj.ipfo_type = IPFOBJ_STATESAVE;
400 if (opts & OPT_VERBOSE)
401 printf("Getting state from addr %p\n", ips.ips_next);
402 if (ioctl(fd, SIOCSTGET, &obj)) {
405 perror("state:SIOCSTGET");
409 if (opts & OPT_VERBOSE)
410 printf("Got state next %p\n", ips.ips_next);
411 if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) {
412 perror("state:write");
416 } while (ips.ips_next != NULL);
423 int readstate(int fd, char *file)
425 ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL;
430 file = IPF_STATEFILE;
432 sfd = open(file, O_RDONLY, 0600);
434 fprintf(stderr, "%s ", file);
439 bzero((char *)&ips, sizeof(ips));
442 * 1. Read all state information in.
445 i = read(sfd, &ips, sizeof(ips));
452 if (i != sizeof(ips)) {
453 fprintf(stderr, "state:incomplete read: %d != %d\n",
454 i, (int)sizeof(ips));
457 is = (ipstate_save_t *)malloc(sizeof(*is));
459 fprintf(stderr, "malloc failed\n");
463 bcopy((char *)&ips, (char *)is, sizeof(ips));
466 * Check to see if this is the first state entry that will
467 * reference a particular rule and if so, flag it as such
468 * else just adjust the rule pointer to become a pointer to
469 * the other. We do this so we have a means later for tracking
470 * who is referencing us when we get back the real pointer
471 * in is_rule after doing the ioctl.
473 for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next)
474 if (is1->ips_rule == is->ips_rule)
477 is->ips_is.is_flags |= SI_NEWFR;
479 is->ips_rule = (void *)&is1->ips_rule;
482 * Use a tail-queue type list (add things to the end)..
488 ipstail->ips_next = is;
494 obj.ipfo_rev = IPFILTER_VERSION;
495 obj.ipfo_size = sizeof(*is);
496 obj.ipfo_type = IPFOBJ_STATESAVE;
498 while ((is = ipshead) != NULL) {
499 if (opts & OPT_VERBOSE)
500 printf("Loading new state table entry\n");
501 if (is->ips_is.is_flags & SI_NEWFR) {
502 if (opts & OPT_VERBOSE)
503 printf("Loading new filter rule\n");
507 if (!(opts & OPT_DONOTHING))
508 if (ioctl(fd, SIOCSTPUT, &obj)) {
513 if (is->ips_is.is_flags & SI_NEWFR) {
514 if (opts & OPT_VERBOSE)
515 printf("Real rule addr %p\n", is->ips_rule);
516 for (is1 = is->ips_next; is1; is1 = is1->ips_next)
517 if (is1->ips_rule == (frentry_t *)&is->ips_rule)
518 is1->ips_rule = is->ips_rule;
521 ipshead = is->ips_next;
528 while ((is = ipshead) != NULL) {
529 ipshead = is->ips_next;
538 int readnat(int fd, char *file)
540 nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL;
555 nfd = open(file, O_RDONLY);
557 fprintf(stderr, "%s ", file);
562 bzero((char *)&ipn, sizeof(ipn));
565 * 1. Read all state information in.
568 i = read(nfd, &ipn, sizeof(ipn));
575 if (i != sizeof(ipn)) {
576 fprintf(stderr, "nat:incomplete read: %d != %d\n",
577 i, (int)sizeof(ipn));
581 in = (nat_save_t *)malloc(ipn.ipn_dsize);
583 fprintf(stderr, "nat:cannot malloc nat save atruct\n");
587 if (ipn.ipn_dsize > sizeof(ipn)) {
588 n = ipn.ipn_dsize - sizeof(ipn);
590 s = in->ipn_data + sizeof(in->ipn_data);
596 "nat:incomplete read: %d != %d\n",
602 bcopy((char *)&ipn, (char *)in, sizeof(ipn));
605 * Check to see if this is the first NAT entry that will
606 * reference a particular rule and if so, flag it as such
607 * else just adjust the rule pointer to become a pointer to
608 * the other. We do this so we have a means later for tracking
609 * who is referencing us when we get back the real pointer
610 * in is_rule after doing the ioctl.
613 if (nat->nat_fr != NULL) {
614 for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next)
615 if (in1->ipn_rule == nat->nat_fr)
618 nat->nat_flags |= SI_NEWFR;
620 nat->nat_fr = &in1->ipn_fr;
624 * Use a tail-queue type list (add things to the end)..
630 ipntail->ipn_next = in;
637 obj.ipfo_rev = IPFILTER_VERSION;
638 obj.ipfo_type = IPFOBJ_NATSAVE;
640 while ((in = ipnhead) != NULL) {
641 if (opts & OPT_VERBOSE)
642 printf("Loading new NAT table entry\n");
644 if (nat->nat_flags & SI_NEWFR) {
645 if (opts & OPT_VERBOSE)
646 printf("Loading new filter rule\n");
650 obj.ipfo_size = in->ipn_dsize;
651 if (!(opts & OPT_DONOTHING))
652 if (ioctl(fd, SIOCSTPUT, &obj)) {
653 fprintf(stderr, "in=%p:", in);
658 if (nat->nat_flags & SI_NEWFR) {
659 if (opts & OPT_VERBOSE)
660 printf("Real rule addr %p\n", nat->nat_fr);
661 for (in1 = in->ipn_next; in1; in1 = in1->ipn_next)
662 if (in1->ipn_rule == &in->ipn_fr)
663 in1->ipn_rule = nat->nat_fr;
666 ipnhead = in->ipn_next;
673 while ((in = ipnhead) != NULL) {
674 ipnhead = in->ipn_next;
683 int writenat(int fd, char *file)
685 nat_save_t *ipnp = NULL, *next = NULL;
693 nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
695 fprintf(stderr, "%s ", file);
700 obj.ipfo_rev = IPFILTER_VERSION;
701 obj.ipfo_type = IPFOBJ_NATSAVE;
704 if (opts & OPT_VERBOSE)
705 printf("Getting nat from addr %p\n", ipnp);
708 if (ioctl(fd, SIOCSTGSZ, &ng)) {
709 perror("nat:SIOCSTGSZ");
716 if (opts & OPT_VERBOSE)
717 printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr);
723 ipnp = malloc(ng.ng_sz);
725 ipnp = realloc((char *)ipnp, ng.ng_sz);
728 "malloc for %d bytes failed\n", ng.ng_sz);
732 bzero((char *)ipnp, ng.ng_sz);
733 obj.ipfo_size = ng.ng_sz;
735 ipnp->ipn_dsize = ng.ng_sz;
736 ipnp->ipn_next = next;
737 if (ioctl(fd, SIOCSTGET, &obj)) {
740 perror("nat:SIOCSTGET");
746 if (opts & OPT_VERBOSE)
747 printf("Got nat next %p ipn_dsize %d ng_sz %d\n",
748 ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz);
749 if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) {
755 next = ipnp->ipn_next;
756 } while (ipnp && next);
765 int writeall(char *dirname)
770 dirname = IPF_SAVEDIR;
772 if (chdir(dirname)) {
773 fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname);
774 perror("chdir(IPF_SAVEDIR)");
778 fd = opendevice(NULL);
781 if (setlock(fd, 1)) {
786 devfd = opendevice(IPSTATE_NAME);
789 if (writestate(devfd, NULL))
793 devfd = opendevice(IPNAT_NAME);
796 if (writenat(devfd, NULL))
800 if (setlock(fd, 0)) {
815 int readall(char *dirname)
820 dirname = IPF_SAVEDIR;
822 if (chdir(dirname)) {
823 perror("chdir(IPF_SAVEDIR)");
827 fd = opendevice(NULL);
830 if (setlock(fd, 1)) {
835 devfd = opendevice(IPSTATE_NAME);
838 if (readstate(devfd, NULL))
842 devfd = opendevice(IPNAT_NAME);
845 if (readnat(devfd, NULL))
849 if (setlock(fd, 0)) {