Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ipf / tools / ipfs.c
blob7ce91c3c54d551515980ecc2c5401297eeaf28be
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2001-2006 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8 #ifdef __FreeBSD__
9 # ifndef __FreeBSD_cc_version
10 # include <osreldate.h>
11 # else
12 # if __FreeBSD_cc_version < 430000
13 # include <osreldate.h>
14 # endif
15 # endif
16 #endif
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <fcntl.h>
21 #include <errno.h>
22 #if !defined(__SVR4) && !defined(__GNUC__)
23 #include <strings.h>
24 #endif
25 #include <sys/types.h>
26 #include <sys/param.h>
27 #include <sys/file.h>
28 #include <stdlib.h>
29 #include <stddef.h>
30 #include <sys/socket.h>
31 #include <sys/ioctl.h>
32 #include <netinet/in.h>
33 #include <netinet/in_systm.h>
34 #include <sys/time.h>
35 #include <net/if.h>
36 #if __FreeBSD_version >= 300000
37 # include <net/if_var.h>
38 #endif
39 #include <netinet/ip.h>
40 #include <netdb.h>
41 #include <arpa/nameser.h>
42 #include <resolv.h>
43 #include "ipf.h"
44 #include "netinet/ipl.h"
46 #if !defined(lint)
47 static const char rcsid[] = "@(#)Id: ipfs.c,v 1.12 2003/12/01 01:56:53 darrenr Exp";
48 #endif
50 #ifndef IPF_SAVEDIR
51 # define IPF_SAVEDIR "/var/db/ipf"
52 #endif
53 #ifndef IPF_NATFILE
54 # define IPF_NATFILE "ipnat.ipf"
55 #endif
56 #ifndef IPF_STATEFILE
57 # define IPF_STATEFILE "ipstate.ipf"
58 #endif
60 #if !defined(__SVR4) && defined(__GNUC__)
61 extern char *index __P((const char *, int));
62 #endif
64 extern char *optarg;
65 extern int optind;
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 *));
81 int opts = 0;
82 char *progname;
85 void usage()
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",
94 progname);
95 exit(1);
100 * Change interface names in state information saved out to disk.
102 int changestateif(ifs, fname)
103 char *ifs, *fname;
105 int fd, olen, nlen, rw;
106 ipstate_save_t ips;
107 off_t pos;
108 char *s;
110 s = strchr(ifs, ',');
111 if (!s)
112 usage();
113 *s++ = '\0';
114 nlen = strlen(s);
115 olen = strlen(ifs);
116 if (nlen >= sizeof(ips.ips_is.is_ifname) ||
117 olen >= sizeof(ips.ips_is.is_ifname))
118 usage();
120 fd = open(fname, O_RDWR);
121 if (fd == -1) {
122 perror("open");
123 exit(1);
126 for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) {
127 rw = 0;
128 if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) {
129 strcpy(ips.ips_is.is_ifname[0], s);
130 rw = 1;
132 if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) {
133 strcpy(ips.ips_is.is_ifname[1], s);
134 rw = 1;
136 if (!strncmp(ips.ips_is.is_ifname[2], ifs, olen + 1)) {
137 strcpy(ips.ips_is.is_ifname[2], s);
138 rw = 1;
140 if (!strncmp(ips.ips_is.is_ifname[3], ifs, olen + 1)) {
141 strcpy(ips.ips_is.is_ifname[3], s);
142 rw = 1;
144 if (rw == 1) {
145 if (lseek(fd, pos, SEEK_SET) != pos) {
146 perror("lseek");
147 exit(1);
149 if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) {
150 perror("write");
151 exit(1);
154 pos = lseek(fd, 0, SEEK_CUR);
156 close(fd);
158 return 0;
163 * Change interface names in NAT information saved out to disk.
165 int changenatif(ifs, fname)
166 char *ifs, *fname;
168 int fd, olen, nlen, rw;
169 nat_save_t ipn;
170 nat_t *nat;
171 off_t pos;
172 char *s;
174 s = strchr(ifs, ',');
175 if (!s)
176 usage();
177 *s++ = '\0';
178 nlen = strlen(s);
179 olen = strlen(ifs);
180 nat = &ipn.ipn_nat;
181 if (nlen >= sizeof(nat->nat_ifnames[0]) ||
182 olen >= sizeof(nat->nat_ifnames[0]))
183 usage();
185 fd = open(fname, O_RDWR);
186 if (fd == -1) {
187 perror("open");
188 exit(1);
191 for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) {
192 rw = 0;
193 if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) {
194 strcpy(nat->nat_ifnames[0], s);
195 rw = 1;
197 if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) {
198 strcpy(nat->nat_ifnames[1], s);
199 rw = 1;
201 if (!strncmp(nat->nat_ifnames[2], ifs, olen + 1)) {
202 strcpy(nat->nat_ifnames[2], s);
203 rw = 1;
205 if (!strncmp(nat->nat_ifnames[3], ifs, olen + 1)) {
206 strcpy(nat->nat_ifnames[3], s);
207 rw = 1;
209 if (rw == 1) {
210 if (lseek(fd, pos, SEEK_SET) != pos) {
211 perror("lseek");
212 exit(1);
214 if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) {
215 perror("write");
216 exit(1);
219 pos = lseek(fd, 0, SEEK_CUR);
221 close(fd);
223 return 0;
227 int main(argc,argv)
228 int argc;
229 char *argv[];
231 int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0;
232 char *dirname = NULL, *filename = NULL, *ifs = NULL;
234 progname = argv[0];
235 while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1)
236 switch (c)
238 case 'd' :
239 if ((set == 0) && !dirname && !filename)
240 dirname = optarg;
241 else
242 usage();
243 break;
244 case 'f' :
245 if ((set != 0) && !dirname && !filename)
246 filename = optarg;
247 else
248 usage();
249 break;
250 case 'i' :
251 ifs = optarg;
252 set = 1;
253 break;
254 case 'l' :
255 if (filename || dirname || set)
256 usage();
257 lock = 1;
258 set = 1;
259 break;
260 case 'n' :
261 opts |= OPT_DONOTHING;
262 break;
263 case 'N' :
264 if ((ns >= 0) || dirname || (rw != -1) || set)
265 usage();
266 ns = 0;
267 set = 1;
268 break;
269 case 'r' :
270 if (dirname || (rw != -1) || (ns == -1))
271 usage();
272 rw = 0;
273 set = 1;
274 break;
275 case 'R' :
276 rw = 2;
277 set = 1;
278 break;
279 case 'S' :
280 if ((ns >= 0) || dirname || (rw != -1) || set)
281 usage();
282 ns = 1;
283 set = 1;
284 break;
285 case 'u' :
286 if (filename || dirname || set)
287 usage();
288 lock = 0;
289 set = 1;
290 break;
291 case 'v' :
292 opts |= OPT_VERBOSE;
293 break;
294 case 'w' :
295 if (dirname || (rw != -1) || (ns == -1))
296 usage();
297 rw = 1;
298 set = 1;
299 break;
300 case 'W' :
301 rw = 3;
302 set = 1;
303 break;
304 case '?' :
305 default :
306 usage();
309 if (ifs) {
310 if (!filename || ns < 0)
311 usage();
312 if (ns == 0)
313 return changenatif(ifs, filename);
314 else
315 return changestateif(ifs, filename);
318 if ((ns >= 0) || (lock >= 0)) {
319 if (lock >= 0)
320 devfd = opendevice(NULL);
321 else if (ns >= 0) {
322 if (ns == 1)
323 devfd = opendevice(IPSTATE_NAME);
324 else if (ns == 0)
325 devfd = opendevice(IPNAT_NAME);
327 if (devfd == -1)
328 exit(1);
331 if (lock >= 0)
332 err = setlock(devfd, lock);
333 else if (rw >= 0) {
334 if (rw & 1) { /* WRITE */
335 if (rw & 2)
336 err = writeall(dirname);
337 else {
338 if (ns == 0)
339 err = writenat(devfd, filename);
340 else if (ns == 1)
341 err = writestate(devfd, filename);
343 } else {
344 if (rw & 2)
345 err = readall(dirname);
346 else {
347 if (ns == 0)
348 err = readnat(devfd, filename);
349 else if (ns == 1)
350 err = readstate(devfd, filename);
354 return err;
358 int opendevice(ipfdev)
359 char *ipfdev;
361 int fd = -1;
363 if (opts & OPT_DONOTHING)
364 return -2;
366 if (!ipfdev)
367 ipfdev = IPL_NAME;
369 if ((fd = open(ipfdev, O_RDWR)) == -1)
370 if ((fd = open(ipfdev, O_RDONLY)) == -1)
371 perror("open device");
372 return fd;
376 void closedevice(fd)
377 int fd;
379 close(fd);
383 int setlock(fd, lock)
384 int 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) {
390 perror("SIOCSTLCK");
391 return 1;
393 if (opts & OPT_VERBOSE)
394 printf("Lock now %s\n", lock ? "on" : "off");
396 return 0;
400 int writestate(fd, file)
401 int fd;
402 char *file;
404 ipstate_save_t ips, *ipsp;
405 ipfobj_t obj;
406 int wfd = -1;
408 if (!file)
409 file = IPF_STATEFILE;
411 wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
412 if (wfd == -1) {
413 fprintf(stderr, "%s ", file);
414 perror("state:open");
415 return 1;
418 ipsp = &ips;
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;
425 obj.ipfo_ptr = ipsp;
427 do {
429 if (opts & OPT_VERBOSE)
430 printf("Getting state from addr %p\n", ips.ips_next);
431 if (ioctl(fd, SIOCSTGET, &obj)) {
432 if (errno == ENOENT)
433 break;
434 perror("state:SIOCSTGET");
435 close(wfd);
436 return 1;
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");
442 close(wfd);
443 return 1;
445 } while (ips.ips_next != NULL);
446 close(wfd);
448 return 0;
452 int readstate(fd, file)
453 int fd;
454 char *file;
456 ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL;
457 int sfd = -1, i;
458 ipfobj_t obj;
460 if (!file)
461 file = IPF_STATEFILE;
463 sfd = open(file, O_RDONLY, 0600);
464 if (sfd == -1) {
465 fprintf(stderr, "%s ", file);
466 perror("open");
467 return 1;
470 bzero((char *)&ips, sizeof(ips));
473 * 1. Read all state information in.
475 do {
476 i = read(sfd, &ips, sizeof(ips));
477 if (i == -1) {
478 perror("read");
479 goto freeipshead;
481 if (i == 0)
482 break;
483 if (i != sizeof(ips)) {
484 fprintf(stderr, "state:incomplete read: %d != %d\n",
485 i, (int)sizeof(ips));
486 goto freeipshead;
488 is = (ipstate_save_t *)malloc(sizeof(*is));
489 if (is == NULL) {
490 fprintf(stderr, "malloc failed\n");
491 goto freeipshead;
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)
506 break;
507 if (is1 == NULL)
508 is->ips_is.is_flags |= SI_NEWFR;
509 else
510 is->ips_rule = (void *)&is1->ips_rule;
513 * Use a tail-queue type list (add things to the end)..
515 is->ips_next = NULL;
516 if (!ipshead)
517 ipshead = is;
518 if (ipstail)
519 ipstail->ips_next = is;
520 ipstail = is;
521 } while (1);
523 close(sfd);
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");
537 obj.ipfo_ptr = is;
538 if (!(opts & OPT_DONOTHING))
539 if (ioctl(fd, SIOCSTPUT, &obj)) {
540 perror("SIOCSTPUT");
541 goto freeipshead;
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;
553 free(is);
556 return 0;
558 freeipshead:
559 while ((is = ipshead) != NULL) {
560 ipshead = is->ips_next;
561 free(is);
563 if (sfd != -1)
564 close(sfd);
565 return 1;
569 int readnat(fd, file)
570 int fd;
571 char *file;
573 nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL;
574 ipfobj_t obj;
575 int nfd, i;
576 nat_t *nat;
577 char *s;
578 int n;
580 nfd = -1;
581 in = NULL;
582 ipnhead = NULL;
583 ipntail = NULL;
585 if (!file)
586 file = IPF_NATFILE;
588 nfd = open(file, O_RDONLY);
589 if (nfd == -1) {
590 fprintf(stderr, "%s ", file);
591 perror("nat:open");
592 return 1;
595 bzero((char *)&ipn, sizeof(ipn));
598 * 1. Read all state information in.
600 do {
601 i = read(nfd, &ipn, sizeof(ipn));
602 if (i == -1) {
603 perror("read");
604 goto freenathead;
606 if (i == 0)
607 break;
608 if (i != sizeof(ipn)) {
609 fprintf(stderr, "nat:incomplete read: %d != %d\n",
610 i, (int)sizeof(ipn));
611 goto freenathead;
614 in = (nat_save_t *)malloc(ipn.ipn_dsize);
615 if (in == NULL) {
616 fprintf(stderr, "nat:cannot malloc nat save atruct\n");
617 goto freenathead;
620 if (ipn.ipn_dsize > sizeof(ipn)) {
621 n = ipn.ipn_dsize - sizeof(ipn);
622 if (n > 0) {
623 s = in->ipn_data + sizeof(in->ipn_data);
624 i = read(nfd, s, n);
625 if (i == 0)
626 break;
627 if (i != n) {
628 fprintf(stderr,
629 "nat:incomplete read: %d != %d\n",
630 i, n);
631 goto freenathead;
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.
645 nat = &in->ipn_nat;
646 if (nat->nat_fr != NULL) {
647 for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next)
648 if (in1->ipn_rule == nat->nat_fr)
649 break;
650 if (in1 == NULL)
651 nat->nat_flags |= SI_NEWFR;
652 else
653 nat->nat_fr = &in1->ipn_fr;
657 * Use a tail-queue type list (add things to the end)..
659 in->ipn_next = NULL;
660 if (!ipnhead)
661 ipnhead = in;
662 if (ipntail)
663 ipntail->ipn_next = in;
664 ipntail = in;
665 } while (1);
667 close(nfd);
668 nfd = -1;
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");
676 nat = &in->ipn_nat;
677 if (nat->nat_flags & SI_NEWFR) {
678 if (opts & OPT_VERBOSE)
679 printf("Loading new filter rule\n");
682 obj.ipfo_ptr = in;
683 obj.ipfo_size = in->ipn_dsize;
684 if (!(opts & OPT_DONOTHING))
685 if (ioctl(fd, SIOCSTPUT, &obj)) {
686 fprintf(stderr, "in=%p:", in);
687 perror("SIOCSTPUT");
688 return 1;
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;
700 free(in);
703 return 0;
705 freenathead:
706 while ((in = ipnhead) != NULL) {
707 ipnhead = in->ipn_next;
708 free(in);
710 if (nfd != -1)
711 close(nfd);
712 return 1;
716 int writenat(fd, file)
717 int fd;
718 char *file;
720 nat_save_t *ipnp = NULL, *next = NULL;
721 ipfobj_t obj;
722 int nfd = -1;
723 natget_t ng;
725 if (!file)
726 file = IPF_NATFILE;
728 nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
729 if (nfd == -1) {
730 fprintf(stderr, "%s ", file);
731 perror("nat:open");
732 return 1;
735 obj.ipfo_rev = IPFILTER_VERSION;
736 obj.ipfo_type = IPFOBJ_NATSAVE;
738 do {
739 if (opts & OPT_VERBOSE)
740 printf("Getting nat from addr %p\n", ipnp);
741 ng.ng_ptr = next;
742 ng.ng_sz = 0;
743 if (ioctl(fd, SIOCSTGSZ, &ng)) {
744 perror("nat:SIOCSTGSZ");
745 close(nfd);
746 if (ipnp != NULL)
747 free(ipnp);
748 return 1;
751 if (opts & OPT_VERBOSE)
752 printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr);
754 if (ng.ng_sz == 0)
755 break;
757 if (!ipnp)
758 ipnp = malloc(ng.ng_sz);
759 else
760 ipnp = realloc((char *)ipnp, ng.ng_sz);
761 if (!ipnp) {
762 fprintf(stderr,
763 "malloc for %d bytes failed\n", ng.ng_sz);
764 break;
767 bzero((char *)ipnp, ng.ng_sz);
768 obj.ipfo_size = ng.ng_sz;
769 obj.ipfo_ptr = ipnp;
770 ipnp->ipn_dsize = ng.ng_sz;
771 ipnp->ipn_next = next;
772 if (ioctl(fd, SIOCSTGET, &obj)) {
773 if (errno == ENOENT)
774 break;
775 perror("nat:SIOCSTGET");
776 close(nfd);
777 free(ipnp);
778 return 1;
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) {
785 perror("nat:write");
786 close(nfd);
787 free(ipnp);
788 return 1;
790 next = ipnp->ipn_next;
791 } while (ipnp && next);
792 if (ipnp != NULL)
793 free(ipnp);
794 close(nfd);
796 return 0;
800 int writeall(dirname)
801 char *dirname;
803 int fd, devfd;
805 if (!dirname)
806 dirname = IPF_SAVEDIR;
808 if (chdir(dirname)) {
809 fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname);
810 perror("chdir(IPF_SAVEDIR)");
811 return 1;
814 fd = opendevice(NULL);
815 if (fd == -1)
816 return 1;
817 if (setlock(fd, 1)) {
818 close(fd);
819 return 1;
822 devfd = opendevice(IPSTATE_NAME);
823 if (devfd == -1)
824 goto bad;
825 if (writestate(devfd, NULL))
826 goto bad;
827 close(devfd);
829 devfd = opendevice(IPNAT_NAME);
830 if (devfd == -1)
831 goto bad;
832 if (writenat(devfd, NULL))
833 goto bad;
834 close(devfd);
836 if (setlock(fd, 0)) {
837 close(fd);
838 return 1;
841 close(fd);
842 return 0;
844 bad:
845 setlock(fd, 0);
846 close(fd);
847 return 1;
851 int readall(dirname)
852 char *dirname;
854 int fd, devfd;
856 if (!dirname)
857 dirname = IPF_SAVEDIR;
859 if (chdir(dirname)) {
860 perror("chdir(IPF_SAVEDIR)");
861 return 1;
864 fd = opendevice(NULL);
865 if (fd == -1)
866 return 1;
867 if (setlock(fd, 1)) {
868 close(fd);
869 return 1;
872 devfd = opendevice(IPSTATE_NAME);
873 if (devfd == -1)
874 return 1;
875 if (readstate(devfd, NULL))
876 return 1;
877 close(devfd);
879 devfd = opendevice(IPNAT_NAME);
880 if (devfd == -1)
881 return 1;
882 if (readnat(devfd, NULL))
883 return 1;
884 close(devfd);
886 if (setlock(fd, 0)) {
887 close(fd);
888 return 1;
891 return 0;