2 * Copyright (C) 1999-2001 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
7 # ifndef __FreeBSD_cc_version
8 # include <osreldate.h>
10 # if __FreeBSD_cc_version < 430000
11 # include <osreldate.h>
20 #if !defined(__SVR4) && !defined(__GNUC__)
23 #include <sys/types.h>
24 #include <sys/param.h>
28 #include <sys/socket.h>
29 #include <sys/ioctl.h>
30 #include <netinet/in.h>
31 #include <netinet/in_systm.h>
34 #if __FreeBSD_version >= 300000
35 # include <net/if_var.h>
37 #include <netinet/ip.h>
39 #include <arpa/nameser.h>
41 #include "ip_compat.h"
48 static const char rcsid
[] = "@(#)$Id: ipfs.c,v 2.6.2.15 2003/05/31 02:12:21 darrenr Exp $";
52 # define IPF_SAVEDIR "/var/db/ipf"
55 # define IPF_NATFILE "ipnat.ipf"
58 # define IPF_STATEFILE "ipstate.ipf"
61 #if !defined(__SVR4) && defined(__GNUC__)
62 extern char *index
__P((const char *, int));
68 int main
__P((int, char *[]));
69 void usage
__P((void));
70 int changestateif
__P((char *, char *));
71 int changenatif
__P((char *, char *));
72 int readstate
__P((int, char *));
73 int readnat
__P((int, char *));
74 int writestate
__P((int, char *));
75 int opendevice
__P((char *));
76 void closedevice
__P((int));
77 int setlock
__P((int, int));
78 int writeall
__P((char *));
79 int readall
__P((char *));
80 int writenat
__P((int, char *));
81 char *concat
__P((char *, char *));
92 usage: %s [-nv] [-d <dir>] -R\n\
93 usage: %s [-nv] [-d <dir>] -W\n\
94 usage: %s [-nv] -N [-f <file> | -d <dir>] -r\n\
95 usage: %s [-nv] -S [-f <file> | -d <dir>] -r\n\
96 usage: %s [-nv] -N [-f <file> | -d <dir>] -w\n\
97 usage: %s [-nv] -S [-f <file> | -d <dir>] -w\n\
98 usage: %s [-nv] -N [-f <filename> | -d <dir> ] -i <if1>,<if2>\n\
99 usage: %s [-nv] -S [-f <filename> | -d <dir> ] -i <if1>,<if2>\n\
100 ", progname
, progname
, progname
, progname
, progname
, progname
,
101 progname
, progname
, progname
, progname
);
107 * Change interface names in state information saved out to disk.
109 int changestateif(ifs
, fname
)
112 int fd
, olen
, nlen
, rw
;
117 s
= strchr(ifs
, ',');
123 if (nlen
>= sizeof(ips
.ips_is
.is_ifname
) ||
124 olen
>= sizeof(ips
.ips_is
.is_ifname
))
127 fd
= open(fname
, O_RDWR
);
133 for (pos
= 0; read(fd
, &ips
, sizeof(ips
)) == sizeof(ips
); ) {
135 if (!strncmp(ips
.ips_is
.is_ifname
[0], ifs
, olen
+ 1)) {
136 strcpy(ips
.ips_is
.is_ifname
[0], s
);
139 if (!strncmp(ips
.ips_is
.is_ifname
[1], ifs
, olen
+ 1)) {
140 strcpy(ips
.ips_is
.is_ifname
[1], s
);
144 if (lseek(fd
, pos
, SEEK_SET
) != pos
) {
148 if (write(fd
, &ips
, sizeof(ips
)) != sizeof(ips
)) {
153 pos
= lseek(fd
, 0, SEEK_CUR
);
162 * Change interface names in NAT information saved out to disk.
164 int changenatif(ifs
, fname
)
167 int fd
, olen
, nlen
, rw
;
173 s
= strchr(ifs
, ',');
180 if (nlen
>= sizeof(nat
->nat_ifname
) || olen
>= sizeof(nat
->nat_ifname
))
183 fd
= open(fname
, O_RDWR
);
189 for (pos
= 0; read(fd
, &ipn
, sizeof(ipn
)) == sizeof(ipn
); ) {
191 if (!strncmp(nat
->nat_ifname
, ifs
, olen
+ 1)) {
192 strcpy(nat
->nat_ifname
, s
);
196 if (lseek(fd
, pos
, SEEK_SET
) != pos
) {
200 if (write(fd
, &ipn
, sizeof(ipn
)) != sizeof(ipn
)) {
205 pos
= lseek(fd
, 0, SEEK_CUR
);
217 int c
, lock
= -1, devfd
= -1, err
= 0, rw
= -1, ns
= -1, set
= 0;
218 char *dirname
= NULL
, *filename
= NULL
, *ifs
= NULL
;
222 while ((c
= getopt(argc
, argv
, "d:f:i:lNnSRruvWw")) != -1)
226 if ((set
== 0) && !dirname
&& !filename
)
232 if ((set
== 1) && !dirname
&& !filename
&& !(rw
& 2))
242 if (filename
|| dirname
|| set
)
248 opts
|= OPT_DONOTHING
;
251 if ((ns
>= 0) || dirname
|| (rw
!= -1) || set
)
257 if (dirname
|| (rw
!= -1) || (ns
== -1))
263 if (filename
|| (ns
!= -1))
269 if ((ns
>= 0) || dirname
|| (rw
!= -1) || set
)
275 if (filename
|| dirname
|| set
)
284 if (dirname
|| (rw
!= -1) || (ns
== -1))
290 if (filename
|| (ns
!= -1))
303 if (filename
== NULL
) {
306 dirname
= IPF_SAVEDIR
;
307 if (dirname
[strlen(dirname
) - 1] != '/')
308 dirname
= concat(dirname
, "/");
309 filename
= concat(dirname
, IPF_NATFILE
);
310 } else if (ns
== 1) {
312 dirname
= IPF_SAVEDIR
;
313 if (dirname
[strlen(dirname
) - 1] != '/')
314 dirname
= concat(dirname
, "/");
315 filename
= concat(dirname
, IPF_STATEFILE
);
320 if (!filename
|| ns
< 0)
323 return changenatif(ifs
, filename
);
325 return changestateif(ifs
, filename
);
328 if ((ns
>= 0) || (lock
>= 0)) {
330 devfd
= opendevice(NULL
);
333 devfd
= opendevice(IPL_STATE
);
335 devfd
= opendevice(IPL_NAT
);
342 err
= setlock(devfd
, lock
);
344 if (rw
& 1) { /* WRITE */
346 err
= writeall(dirname
);
349 err
= writenat(devfd
, filename
);
351 err
= writestate(devfd
, filename
);
355 err
= readall(dirname
);
358 err
= readnat(devfd
, filename
);
360 err
= readstate(devfd
, filename
);
368 char *concat(base
, append
)
373 str
= malloc(strlen(base
) + strlen(append
) + 1);
382 int opendevice(ipfdev
)
387 if (opts
& OPT_DONOTHING
)
393 if ((fd
= open(ipfdev
, O_RDWR
)) == -1)
394 if ((fd
= open(ipfdev
, O_RDONLY
)) == -1)
395 perror("open device");
407 int setlock(fd
, lock
)
410 if (opts
& OPT_VERBOSE
)
411 printf("Turn lock %s\n", lock
? "on" : "off");
412 if (!(opts
& OPT_DONOTHING
)) {
413 if (ioctl(fd
, SIOCSTLCK
, &lock
) == -1) {
417 if (opts
& OPT_VERBOSE
)
418 printf("Lock now %s\n", lock
? "on" : "off");
424 int writestate(fd
, file
)
428 ipstate_save_t ips
, *ipsp
;
432 file
= IPF_STATEFILE
;
434 wfd
= open(file
, O_WRONLY
|O_TRUNC
|O_CREAT
, 0600);
436 fprintf(stderr
, "%s ", file
);
437 perror("state:open");
442 bzero((char *)ipsp
, sizeof(ips
));
445 if (opts
& OPT_VERBOSE
)
446 printf("Getting state from addr %p\n", ips
.ips_next
);
447 if (ioctl(fd
, SIOCSTGET
, &ipsp
)) {
450 perror("state:SIOCSTGET");
454 if (opts
& OPT_VERBOSE
)
455 printf("Got state next %p\n", ips
.ips_next
);
456 if (write(wfd
, ipsp
, sizeof(ips
)) != sizeof(ips
)) {
457 perror("state:write");
461 } while (ips
.ips_next
!= NULL
);
468 int readstate(fd
, file
)
472 ipstate_save_t ips
, *is
, *ipshead
= NULL
, *is1
, *ipstail
= NULL
;
476 file
= IPF_STATEFILE
;
478 sfd
= open(file
, O_RDONLY
, 0600);
480 fprintf(stderr
, "%s ", file
);
485 bzero((char *)&ips
, sizeof(ips
));
488 * 1. Read all state information in.
491 i
= read(sfd
, &ips
, sizeof(ips
));
499 if (i
!= sizeof(ips
)) {
500 fprintf(stderr
, "incomplete read: %d != %d\n", i
,
505 is
= (ipstate_save_t
*)malloc(sizeof(*is
));
507 fprintf(stderr
, "malloc failed\n");
511 bcopy((char *)&ips
, (char *)is
, sizeof(ips
));
514 * Check to see if this is the first state entry that will
515 * reference a particular rule and if so, flag it as such
516 * else just adjust the rule pointer to become a pointer to
517 * the other. We do this so we have a means later for tracking
518 * who is referencing us when we get back the real pointer
519 * in is_rule after doing the ioctl.
521 for (is1
= ipshead
; is1
!= NULL
; is1
= is1
->ips_next
)
522 if (is1
->ips_rule
== is
->ips_rule
)
525 is
->ips_is
.is_flags
|= FI_NEWFR
;
527 is
->ips_rule
= (void *)&is1
->ips_rule
;
530 * Use a tail-queue type list (add things to the end)..
536 ipstail
->ips_next
= is
;
542 for (is
= ipshead
; is
; is
= is
->ips_next
) {
543 if (opts
& OPT_VERBOSE
)
544 printf("Loading new state table entry\n");
545 if (is
->ips_is
.is_flags
& FI_NEWFR
) {
546 if (opts
& OPT_VERBOSE
)
547 printf("Loading new filter rule\n");
549 if (!(opts
& OPT_DONOTHING
))
550 if (ioctl(fd
, SIOCSTPUT
, &is
)) {
555 if (is
->ips_is
.is_flags
& FI_NEWFR
) {
556 if (opts
& OPT_VERBOSE
)
557 printf("Real rule addr %p\n", is
->ips_rule
);
558 for (is1
= is
->ips_next
; is1
; is1
= is1
->ips_next
)
559 if (is1
->ips_rule
== (frentry_t
*)&is
->ips_rule
)
560 is1
->ips_rule
= is
->ips_rule
;
568 int readnat(fd
, file
)
572 nat_save_t ipn
, *in
, *ipnhead
= NULL
, *in1
, *ipntail
= NULL
;
581 nfd
= open(file
, O_RDONLY
);
583 fprintf(stderr
, "%s ", file
);
588 bzero((char *)&ipn
, sizeof(ipn
));
591 * 1. Read all state information in.
594 i
= read(nfd
, &ipn
, sizeof(ipn
));
602 if (i
!= sizeof(ipn
)) {
603 fprintf(stderr
, "incomplete read: %d != %d\n", i
,
609 if (ipn
.ipn_dsize
> 0) {
612 if (n
> sizeof(ipn
.ipn_data
))
613 n
-= sizeof(ipn
.ipn_data
);
616 in
= malloc(sizeof(*in
) + n
);
621 s
= in
->ipn_data
+ sizeof(in
->ipn_data
);
627 "incomplete read: %d != %d\n",
634 in
= (nat_save_t
*)malloc(sizeof(*in
));
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
|= FI_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 for (in
= ipnhead
; in
; in
= in
->ipn_next
) {
671 if (opts
& OPT_VERBOSE
)
672 printf("Loading new NAT table entry\n");
674 if (nat
->nat_flags
& FI_NEWFR
) {
675 if (opts
& OPT_VERBOSE
)
676 printf("Loading new filter rule\n");
678 if (!(opts
& OPT_DONOTHING
))
679 if (ioctl(fd
, SIOCSTPUT
, &in
)) {
684 if (nat
->nat_flags
& FI_NEWFR
) {
685 if (opts
& OPT_VERBOSE
)
686 printf("Real rule addr %p\n", nat
->nat_fr
);
687 for (in1
= in
->ipn_next
; in1
; in1
= in1
->ipn_next
)
688 if (in1
->ipn_rule
== &in
->ipn_fr
)
689 in1
->ipn_rule
= nat
->nat_fr
;
697 int writenat(fd
, file
)
701 nat_save_t
*ipnp
= NULL
, *next
= NULL
;
708 nfd
= open(file
, O_WRONLY
|O_TRUNC
|O_CREAT
, 0600);
710 fprintf(stderr
, "%s ", file
);
717 if (opts
& OPT_VERBOSE
)
718 printf("Getting nat from addr %p\n", ipnp
);
721 if (ioctl(fd
, SIOCSTGSZ
, &ng
)) {
722 perror("nat:SIOCSTGSZ");
727 if (opts
& OPT_VERBOSE
)
728 printf("NAT size %d from %p\n", ng
.ng_sz
, ng
.ng_ptr
);
734 ipnp
= malloc(ng
.ng_sz
);
736 ipnp
= realloc((char *)ipnp
, ng
.ng_sz
);
739 "malloc for %d bytes failed\n", ng
.ng_sz
);
743 bzero((char *)ipnp
, ng
.ng_sz
);
744 ipnp
->ipn_next
= next
;
745 if (ioctl(fd
, SIOCSTGET
, &ipnp
)) {
748 perror("nat:SIOCSTGET");
753 if (opts
& OPT_VERBOSE
)
754 printf("Got nat next %p\n", ipnp
->ipn_next
);
755 if (write(nfd
, ipnp
, ng
.ng_sz
) != ng
.ng_sz
) {
760 next
= ipnp
->ipn_next
;
761 } while (ipnp
&& next
);
768 int writeall(dirname
)
774 dirname
= IPF_SAVEDIR
;
776 if (chdir(dirname
)) {
777 fprintf(stderr
, "IPF_SAVEDIR=%s: ", dirname
);
778 perror("chdir(IPF_SAVEDIR)");
782 fd
= opendevice(NULL
);
785 if (setlock(fd
, 1)) {
790 devfd
= opendevice(IPL_STATE
);
793 if (writestate(devfd
, NULL
))
797 devfd
= opendevice(IPL_NAT
);
800 if (writenat(devfd
, NULL
))
804 if (setlock(fd
, 0)) {
824 dirname
= IPF_SAVEDIR
;
826 if (chdir(dirname
)) {
827 perror("chdir(IPF_SAVEDIR)");
831 fd
= opendevice(NULL
);
834 if (setlock(fd
, 1)) {
839 devfd
= opendevice(IPL_STATE
);
842 if (readstate(devfd
, NULL
))
846 devfd
= opendevice(IPL_NAT
);
849 if (readnat(devfd
, NULL
))
853 if (setlock(fd
, 0)) {