2 * Copyright (C) 1999-2001, 2003 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
6 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
7 * Use is subject to license terms.
9 * Copyright (c) 2014, Joyent, Inc. All rights reserved.
13 # ifndef __FreeBSD_cc_version
14 # include <osreldate.h>
16 # if __FreeBSD_cc_version < 430000
17 # include <osreldate.h>
26 #if !defined(__SVR4) && !defined(__GNUC__)
29 #include <sys/types.h>
30 #include <sys/param.h>
34 #include <sys/socket.h>
35 #include <sys/ioctl.h>
36 #include <netinet/in.h>
37 #include <netinet/in_systm.h>
40 #if __FreeBSD_version >= 300000
41 # include <net/if_var.h>
43 #include <netinet/ip.h>
45 #include <arpa/nameser.h>
48 #include "netinet/ipl.h"
51 static const char rcsid
[] = "@(#)Id: ipfs.c,v 1.12 2003/12/01 01:56:53 darrenr Exp";
54 # define IPF_SAVEDIR "/var/db/ipf"
57 # define IPF_NATFILE "ipnat.ipf"
60 # define IPF_STATEFILE "ipstate.ipf"
63 #if !defined(__SVR4) && defined(__GNUC__)
64 extern char *index
__P((const char *, int));
70 int main
__P((int, char *[]));
71 void usage
__P((void));
72 int changestateif
__P((char *, char *));
73 int changenatif
__P((char *, char *));
74 int readstate
__P((int, char *));
75 int readnat
__P((int, char *));
76 int writestate
__P((int, char *));
77 int opendevice
__P((char *));
78 void closedevice
__P((int));
79 int setlock
__P((int, int));
80 int writeall
__P((char *));
81 int readall
__P((char *));
82 int writenat
__P((int, char *));
90 const char *zoneopt
= "[-G|-z zonename] ";
91 fprintf(stderr
, "usage: %s %s[-nv] -l\n", progname
, zoneopt
);
92 fprintf(stderr
, "usage: %s %s[-nv] -u\n", progname
, zoneopt
);
93 fprintf(stderr
, "usage: %s %s[-nv] [-d <dir>] -R\n", progname
, zoneopt
);
94 fprintf(stderr
, "usage: %s %s[-nv] [-d <dir>] -W\n", progname
, zoneopt
);
95 fprintf(stderr
, "usage: %s %s[-nv] [-N|-S] [-f <file>] -r\n", progname
,
97 fprintf(stderr
, "usage: %s %s[-nv] [-N|-S] [-f <file>] -w\n", progname
,
99 fprintf(stderr
, "usage: %s %s[-nv] [-N|-S] -f <file> -i <if1>,<if2>\n",
106 * Change interface names in state information saved out to disk.
108 int changestateif(ifs
, fname
)
111 int fd
, olen
, nlen
, rw
;
116 s
= strchr(ifs
, ',');
122 if (nlen
>= sizeof(ips
.ips_is
.is_ifname
) ||
123 olen
>= sizeof(ips
.ips_is
.is_ifname
))
126 fd
= open(fname
, O_RDWR
);
132 for (pos
= 0; read(fd
, &ips
, sizeof(ips
)) == sizeof(ips
); ) {
134 if (!strncmp(ips
.ips_is
.is_ifname
[0], ifs
, olen
+ 1)) {
135 strcpy(ips
.ips_is
.is_ifname
[0], s
);
138 if (!strncmp(ips
.ips_is
.is_ifname
[1], ifs
, olen
+ 1)) {
139 strcpy(ips
.ips_is
.is_ifname
[1], s
);
143 if (lseek(fd
, pos
, SEEK_SET
) != pos
) {
147 if (write(fd
, &ips
, sizeof(ips
)) != sizeof(ips
)) {
152 pos
= lseek(fd
, 0, SEEK_CUR
);
161 * Change interface names in NAT information saved out to disk.
163 int changenatif(ifs
, fname
)
166 int fd
, olen
, nlen
, rw
;
172 s
= strchr(ifs
, ',');
179 if (nlen
>= sizeof(nat
->nat_ifnames
[0]) ||
180 olen
>= sizeof(nat
->nat_ifnames
[0]))
183 fd
= open(fname
, O_RDWR
);
189 for (pos
= 0; read(fd
, &ipn
, sizeof(ipn
)) == sizeof(ipn
); ) {
191 if (!strncmp(nat
->nat_ifnames
[0], ifs
, olen
+ 1)) {
192 strcpy(nat
->nat_ifnames
[0], s
);
195 if (!strncmp(nat
->nat_ifnames
[1], ifs
, olen
+ 1)) {
196 strcpy(nat
->nat_ifnames
[1], s
);
200 if (lseek(fd
, pos
, SEEK_SET
) != pos
) {
204 if (write(fd
, &ipn
, sizeof(ipn
)) != sizeof(ipn
)) {
209 pos
= lseek(fd
, 0, SEEK_CUR
);
221 int c
, lock
= -1, devfd
= -1, err
= 0, rw
= -1, ns
= -1, set
= 0;
222 char *dirname
= NULL
, *filename
= NULL
, *ifs
= NULL
;
225 while ((c
= getopt(argc
, argv
, "d:f:G:lNnSRruvWwz:")) != -1)
229 if ((set
== 0) && !dirname
&& !filename
)
235 if ((set
== 0) && !dirname
&& !filename
)
241 setzonename_global(optarg
);
248 if (filename
|| dirname
|| set
)
254 opts
|= OPT_DONOTHING
;
257 if ((ns
>= 0) || dirname
|| (rw
!= -1) || set
)
263 if (dirname
|| (rw
!= -1) || (ns
== -1))
273 if ((ns
>= 0) || dirname
|| (rw
!= -1) || set
)
279 if (filename
|| dirname
|| set
)
288 if (dirname
|| (rw
!= -1) || (ns
== -1))
306 if (!filename
|| ns
< 0)
309 return changenatif(ifs
, filename
);
311 return changestateif(ifs
, filename
);
314 if ((ns
>= 0) || (lock
>= 0)) {
316 devfd
= opendevice(NULL
);
319 devfd
= opendevice(IPSTATE_NAME
);
321 devfd
= opendevice(IPNAT_NAME
);
328 err
= setlock(devfd
, lock
);
330 if (rw
& 1) { /* WRITE */
332 err
= writeall(dirname
);
335 err
= writenat(devfd
, filename
);
337 err
= writestate(devfd
, filename
);
341 err
= readall(dirname
);
344 err
= readnat(devfd
, filename
);
346 err
= readstate(devfd
, filename
);
354 int opendevice(ipfdev
)
359 if (opts
& OPT_DONOTHING
)
365 if ((fd
= open(ipfdev
, O_RDWR
)) == -1)
366 if ((fd
= open(ipfdev
, O_RDONLY
)) == -1)
367 perror("open device");
369 if (setzone(fd
) != 0) {
385 int setlock(fd
, lock
)
388 if (opts
& OPT_VERBOSE
)
389 printf("Turn lock %s\n", lock
? "on" : "off");
390 if (!(opts
& OPT_DONOTHING
)) {
391 if (ioctl(fd
, SIOCSTLCK
, &lock
) == -1) {
395 if (opts
& OPT_VERBOSE
)
396 printf("Lock now %s\n", lock
? "on" : "off");
402 int writestate(fd
, file
)
406 ipstate_save_t ips
, *ipsp
;
411 file
= IPF_STATEFILE
;
413 wfd
= open(file
, O_WRONLY
|O_TRUNC
|O_CREAT
, 0600);
415 fprintf(stderr
, "%s ", file
);
416 perror("state:open");
421 bzero((char *)&obj
, sizeof(obj
));
422 bzero((char *)ipsp
, sizeof(ips
));
424 obj
.ipfo_rev
= IPFILTER_VERSION
;
425 obj
.ipfo_size
= sizeof(*ipsp
);
426 obj
.ipfo_type
= IPFOBJ_STATESAVE
;
431 if (opts
& OPT_VERBOSE
)
432 printf("Getting state from addr %p\n", ips
.ips_next
);
433 if (ioctl(fd
, SIOCSTGET
, &obj
)) {
436 perror("state:SIOCSTGET");
440 if (opts
& OPT_VERBOSE
)
441 printf("Got state next %p\n", ips
.ips_next
);
442 if (write(wfd
, ipsp
, sizeof(ips
)) != sizeof(ips
)) {
443 perror("state:write");
447 } while (ips
.ips_next
!= NULL
);
454 int readstate(fd
, file
)
458 ipstate_save_t ips
, *is
, *ipshead
= NULL
, *is1
, *ipstail
= NULL
;
463 file
= IPF_STATEFILE
;
465 sfd
= open(file
, O_RDONLY
, 0600);
467 fprintf(stderr
, "%s ", file
);
472 bzero((char *)&ips
, sizeof(ips
));
475 * 1. Read all state information in.
478 i
= read(sfd
, &ips
, sizeof(ips
));
486 if (i
!= sizeof(ips
)) {
487 fprintf(stderr
, "state:incomplete read: %d != %d\n",
488 i
, (int)sizeof(ips
));
492 is
= (ipstate_save_t
*)malloc(sizeof(*is
));
494 fprintf(stderr
, "malloc failed\n");
498 bcopy((char *)&ips
, (char *)is
, sizeof(ips
));
501 * Check to see if this is the first state entry that will
502 * reference a particular rule and if so, flag it as such
503 * else just adjust the rule pointer to become a pointer to
504 * the other. We do this so we have a means later for tracking
505 * who is referencing us when we get back the real pointer
506 * in is_rule after doing the ioctl.
508 for (is1
= ipshead
; is1
!= NULL
; is1
= is1
->ips_next
)
509 if (is1
->ips_rule
== is
->ips_rule
)
512 is
->ips_is
.is_flags
|= SI_NEWFR
;
514 is
->ips_rule
= (void *)&is1
->ips_rule
;
517 * Use a tail-queue type list (add things to the end)..
523 ipstail
->ips_next
= is
;
529 obj
.ipfo_rev
= IPFILTER_VERSION
;
530 obj
.ipfo_size
= sizeof(*is
);
531 obj
.ipfo_type
= IPFOBJ_STATESAVE
;
533 for (is
= ipshead
; is
; is
= is
->ips_next
) {
534 if (opts
& OPT_VERBOSE
)
535 printf("Loading new state table entry\n");
536 if (is
->ips_is
.is_flags
& SI_NEWFR
) {
537 if (opts
& OPT_VERBOSE
)
538 printf("Loading new filter rule\n");
542 if (!(opts
& OPT_DONOTHING
))
543 if (ioctl(fd
, SIOCSTPUT
, &obj
)) {
548 if (is
->ips_is
.is_flags
& SI_NEWFR
) {
549 if (opts
& OPT_VERBOSE
)
550 printf("Real rule addr %p\n", is
->ips_rule
);
551 for (is1
= is
->ips_next
; is1
; is1
= is1
->ips_next
)
552 if (is1
->ips_rule
== (frentry_t
*)&is
->ips_rule
)
553 is1
->ips_rule
= is
->ips_rule
;
561 int readnat(fd
, file
)
565 nat_save_t ipn
, *in
, *ipnhead
= NULL
, *in1
, *ipntail
= NULL
;
580 nfd
= open(file
, O_RDONLY
);
582 fprintf(stderr
, "%s ", file
);
587 bzero((char *)&ipn
, sizeof(ipn
));
590 * 1. Read all state information in.
593 i
= read(nfd
, &ipn
, sizeof(ipn
));
601 if (i
!= sizeof(ipn
)) {
602 fprintf(stderr
, "nat:incomplete read: %d != %d\n",
603 i
, (int)sizeof(ipn
));
608 in
= (nat_save_t
*)malloc(ipn
.ipn_dsize
);
612 if (ipn
.ipn_dsize
> sizeof(ipn
)) {
613 n
= ipn
.ipn_dsize
- sizeof(ipn
);
615 s
= in
->ipn_data
+ sizeof(in
->ipn_data
);
621 "nat:incomplete read: %d != %d\n",
628 bcopy((char *)&ipn
, (char *)in
, sizeof(ipn
));
631 * Check to see if this is the first NAT entry that will
632 * reference a particular rule and if so, flag it as such
633 * else just adjust the rule pointer to become a pointer to
634 * the other. We do this so we have a means later for tracking
635 * who is referencing us when we get back the real pointer
636 * in is_rule after doing the ioctl.
639 if (nat
->nat_fr
!= NULL
) {
640 for (in1
= ipnhead
; in1
!= NULL
; in1
= in1
->ipn_next
)
641 if (in1
->ipn_rule
== nat
->nat_fr
)
644 nat
->nat_flags
|= SI_NEWFR
;
646 nat
->nat_fr
= &in1
->ipn_fr
;
650 * Use a tail-queue type list (add things to the end)..
656 ipntail
->ipn_next
= in
;
663 obj
.ipfo_rev
= IPFILTER_VERSION
;
664 obj
.ipfo_type
= IPFOBJ_NATSAVE
;
666 for (in
= ipnhead
; in
; in
= in
->ipn_next
) {
667 if (opts
& OPT_VERBOSE
)
668 printf("Loading new NAT table entry\n");
670 if (nat
->nat_flags
& SI_NEWFR
) {
671 if (opts
& OPT_VERBOSE
)
672 printf("Loading new filter rule\n");
676 obj
.ipfo_size
= in
->ipn_dsize
;
677 if (!(opts
& OPT_DONOTHING
))
678 if (ioctl(fd
, SIOCSTPUT
, &obj
)) {
679 fprintf(stderr
, "in=%p:", in
);
684 if (nat
->nat_flags
& SI_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
;
709 nfd
= open(file
, O_WRONLY
|O_TRUNC
|O_CREAT
, 0600);
711 fprintf(stderr
, "%s ", file
);
716 obj
.ipfo_rev
= IPFILTER_VERSION
;
717 obj
.ipfo_type
= IPFOBJ_NATSAVE
;
720 if (opts
& OPT_VERBOSE
)
721 printf("Getting nat from addr %p\n", ipnp
);
724 if (ioctl(fd
, SIOCSTGSZ
, &ng
)) {
725 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
);
779 int writeall(dirname
)
785 dirname
= IPF_SAVEDIR
;
787 if (chdir(dirname
)) {
788 fprintf(stderr
, "IPF_SAVEDIR=%s: ", dirname
);
789 perror("chdir(IPF_SAVEDIR)");
793 fd
= opendevice(NULL
);
796 if (setlock(fd
, 1)) {
801 devfd
= opendevice(IPSTATE_NAME
);
804 if (writestate(devfd
, NULL
))
808 devfd
= opendevice(IPNAT_NAME
);
811 if (writenat(devfd
, NULL
))
815 if (setlock(fd
, 0)) {
836 dirname
= IPF_SAVEDIR
;
838 if (chdir(dirname
)) {
839 perror("chdir(IPF_SAVEDIR)");
843 fd
= opendevice(NULL
);
846 if (setlock(fd
, 1)) {
851 devfd
= opendevice(IPSTATE_NAME
);
854 if (readstate(devfd
, NULL
))
858 devfd
= opendevice(IPNAT_NAME
);
861 if (readnat(devfd
, NULL
))
865 if (setlock(fd
, 0)) {