141edb306SCy Schubert /* $FreeBSD$ */ 241edb306SCy Schubert 341edb306SCy Schubert /* 441edb306SCy Schubert * Copyright (C) 2012 by Darren Reed. 541edb306SCy Schubert * 641edb306SCy Schubert * See the IPFILTER.LICENCE file for details on licencing. 741edb306SCy Schubert */ 841edb306SCy Schubert #include <stdio.h> 941edb306SCy Schubert #include <unistd.h> 1041edb306SCy Schubert #include <string.h> 1141edb306SCy Schubert #include <fcntl.h> 1241edb306SCy Schubert #include <errno.h> 1341edb306SCy Schubert #if !defined(__SVR4) && !defined(__GNUC__) 1441edb306SCy Schubert #include <strings.h> 1541edb306SCy Schubert #endif 1641edb306SCy Schubert #include <sys/types.h> 1741edb306SCy Schubert #include <sys/param.h> 1841edb306SCy Schubert #include <sys/file.h> 1941edb306SCy Schubert #include <stdlib.h> 2041edb306SCy Schubert #include <stddef.h> 2141edb306SCy Schubert #include <sys/socket.h> 2241edb306SCy Schubert #include <sys/ioctl.h> 2341edb306SCy Schubert #include <netinet/in.h> 2441edb306SCy Schubert #include <netinet/in_systm.h> 2541edb306SCy Schubert #include <sys/time.h> 2641edb306SCy Schubert #include <net/if.h> 2741edb306SCy Schubert #include <netinet/ip.h> 2841edb306SCy Schubert #include <netdb.h> 2941edb306SCy Schubert #include <arpa/nameser.h> 3041edb306SCy Schubert #include <resolv.h> 3141edb306SCy Schubert #include "ipf.h" 3241edb306SCy Schubert #include "netinet/ipl.h" 3341edb306SCy Schubert 3441edb306SCy Schubert #if !defined(lint) 3541edb306SCy Schubert static const char rcsid[] = "@(#)$Id$"; 3641edb306SCy Schubert #endif 3741edb306SCy Schubert 3841edb306SCy Schubert #ifndef IPF_SAVEDIR 3941edb306SCy Schubert # define IPF_SAVEDIR "/var/db/ipf" 4041edb306SCy Schubert #endif 4141edb306SCy Schubert #ifndef IPF_NATFILE 4241edb306SCy Schubert # define IPF_NATFILE "ipnat.ipf" 4341edb306SCy Schubert #endif 4441edb306SCy Schubert #ifndef IPF_STATEFILE 4541edb306SCy Schubert # define IPF_STATEFILE "ipstate.ipf" 4641edb306SCy Schubert #endif 4741edb306SCy Schubert 4841edb306SCy Schubert #if !defined(__SVR4) && defined(__GNUC__) 4941edb306SCy Schubert extern char *index(const char *, int); 5041edb306SCy Schubert #endif 5141edb306SCy Schubert 5241edb306SCy Schubert extern char *optarg; 5341edb306SCy Schubert extern int optind; 5441edb306SCy Schubert 5541edb306SCy Schubert int main(int, char *[]); 5641edb306SCy Schubert void usage(void); 5741edb306SCy Schubert int changestateif(char *, char *); 5841edb306SCy Schubert int changenatif(char *, char *); 5941edb306SCy Schubert int readstate(int, char *); 6041edb306SCy Schubert int readnat(int, char *); 6141edb306SCy Schubert int writestate(int, char *); 6241edb306SCy Schubert int opendevice(char *); 6341edb306SCy Schubert void closedevice(int); 6441edb306SCy Schubert int setlock(int, int); 6541edb306SCy Schubert int writeall(char *); 6641edb306SCy Schubert int readall(char *); 6741edb306SCy Schubert int writenat(int, char *); 6841edb306SCy Schubert 6941edb306SCy Schubert int opts = 0; 7041edb306SCy Schubert char *progname; 7141edb306SCy Schubert 7241edb306SCy Schubert 7341edb306SCy Schubert void usage() 7441edb306SCy Schubert { 7541edb306SCy Schubert fprintf(stderr, "usage: %s [-nv] -l\n", progname); 7641edb306SCy Schubert fprintf(stderr, "usage: %s [-nv] -u\n", progname); 7741edb306SCy Schubert fprintf(stderr, "usage: %s [-nv] [-d <dir>] -R\n", progname); 7841edb306SCy Schubert fprintf(stderr, "usage: %s [-nv] [-d <dir>] -W\n", progname); 7941edb306SCy Schubert fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -r\n", progname); 8041edb306SCy Schubert fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -w\n", progname); 8141edb306SCy Schubert fprintf(stderr, "usage: %s [-nNSv] -f <filename> -i <if1>,<if2>\n", 8241edb306SCy Schubert progname); 8341edb306SCy Schubert exit(1); 8441edb306SCy Schubert } 8541edb306SCy Schubert 8641edb306SCy Schubert 8741edb306SCy Schubert /* 8841edb306SCy Schubert * Change interface names in state information saved out to disk. 8941edb306SCy Schubert */ 90*efeb8bffSCy Schubert int changestateif(char *ifs, char *fname) 9141edb306SCy Schubert { 9241edb306SCy Schubert int fd, olen, nlen, rw; 9341edb306SCy Schubert ipstate_save_t ips; 9441edb306SCy Schubert off_t pos; 9541edb306SCy Schubert char *s; 9641edb306SCy Schubert 9741edb306SCy Schubert s = strchr(ifs, ','); 9841edb306SCy Schubert if (!s) 9941edb306SCy Schubert usage(); 10041edb306SCy Schubert *s++ = '\0'; 10141edb306SCy Schubert nlen = strlen(s); 10241edb306SCy Schubert olen = strlen(ifs); 10341edb306SCy Schubert if (nlen >= sizeof(ips.ips_is.is_ifname) || 10441edb306SCy Schubert olen >= sizeof(ips.ips_is.is_ifname)) 10541edb306SCy Schubert usage(); 10641edb306SCy Schubert 10741edb306SCy Schubert fd = open(fname, O_RDWR); 10841edb306SCy Schubert if (fd == -1) { 10941edb306SCy Schubert perror("open"); 11041edb306SCy Schubert exit(1); 11141edb306SCy Schubert } 11241edb306SCy Schubert 11341edb306SCy Schubert for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) { 11441edb306SCy Schubert rw = 0; 11541edb306SCy Schubert if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) { 11641edb306SCy Schubert strcpy(ips.ips_is.is_ifname[0], s); 11741edb306SCy Schubert rw = 1; 11841edb306SCy Schubert } 11941edb306SCy Schubert if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) { 12041edb306SCy Schubert strcpy(ips.ips_is.is_ifname[1], s); 12141edb306SCy Schubert rw = 1; 12241edb306SCy Schubert } 12341edb306SCy Schubert if (!strncmp(ips.ips_is.is_ifname[2], ifs, olen + 1)) { 12441edb306SCy Schubert strcpy(ips.ips_is.is_ifname[2], s); 12541edb306SCy Schubert rw = 1; 12641edb306SCy Schubert } 12741edb306SCy Schubert if (!strncmp(ips.ips_is.is_ifname[3], ifs, olen + 1)) { 12841edb306SCy Schubert strcpy(ips.ips_is.is_ifname[3], s); 12941edb306SCy Schubert rw = 1; 13041edb306SCy Schubert } 13141edb306SCy Schubert if (rw == 1) { 13241edb306SCy Schubert if (lseek(fd, pos, SEEK_SET) != pos) { 13341edb306SCy Schubert perror("lseek"); 13441edb306SCy Schubert exit(1); 13541edb306SCy Schubert } 13641edb306SCy Schubert if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) { 13741edb306SCy Schubert perror("write"); 13841edb306SCy Schubert exit(1); 13941edb306SCy Schubert } 14041edb306SCy Schubert } 14141edb306SCy Schubert pos = lseek(fd, 0, SEEK_CUR); 14241edb306SCy Schubert } 14341edb306SCy Schubert close(fd); 14441edb306SCy Schubert 14541edb306SCy Schubert return 0; 14641edb306SCy Schubert } 14741edb306SCy Schubert 14841edb306SCy Schubert 14941edb306SCy Schubert /* 15041edb306SCy Schubert * Change interface names in NAT information saved out to disk. 15141edb306SCy Schubert */ 152*efeb8bffSCy Schubert int changenatif(char *ifs, char *fname) 15341edb306SCy Schubert { 15441edb306SCy Schubert int fd, olen, nlen, rw; 15541edb306SCy Schubert nat_save_t ipn; 15641edb306SCy Schubert nat_t *nat; 15741edb306SCy Schubert off_t pos; 15841edb306SCy Schubert char *s; 15941edb306SCy Schubert 16041edb306SCy Schubert s = strchr(ifs, ','); 16141edb306SCy Schubert if (!s) 16241edb306SCy Schubert usage(); 16341edb306SCy Schubert *s++ = '\0'; 16441edb306SCy Schubert nlen = strlen(s); 16541edb306SCy Schubert olen = strlen(ifs); 16641edb306SCy Schubert nat = &ipn.ipn_nat; 16741edb306SCy Schubert if (nlen >= sizeof(nat->nat_ifnames[0]) || 16841edb306SCy Schubert olen >= sizeof(nat->nat_ifnames[0])) 16941edb306SCy Schubert usage(); 17041edb306SCy Schubert 17141edb306SCy Schubert fd = open(fname, O_RDWR); 17241edb306SCy Schubert if (fd == -1) { 17341edb306SCy Schubert perror("open"); 17441edb306SCy Schubert exit(1); 17541edb306SCy Schubert } 17641edb306SCy Schubert 17741edb306SCy Schubert for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) { 17841edb306SCy Schubert rw = 0; 17941edb306SCy Schubert if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) { 18041edb306SCy Schubert strcpy(nat->nat_ifnames[0], s); 18141edb306SCy Schubert rw = 1; 18241edb306SCy Schubert } 18341edb306SCy Schubert if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) { 18441edb306SCy Schubert strcpy(nat->nat_ifnames[1], s); 18541edb306SCy Schubert rw = 1; 18641edb306SCy Schubert } 18741edb306SCy Schubert if (rw == 1) { 18841edb306SCy Schubert if (lseek(fd, pos, SEEK_SET) != pos) { 18941edb306SCy Schubert perror("lseek"); 19041edb306SCy Schubert exit(1); 19141edb306SCy Schubert } 19241edb306SCy Schubert if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) { 19341edb306SCy Schubert perror("write"); 19441edb306SCy Schubert exit(1); 19541edb306SCy Schubert } 19641edb306SCy Schubert } 19741edb306SCy Schubert pos = lseek(fd, 0, SEEK_CUR); 19841edb306SCy Schubert } 19941edb306SCy Schubert close(fd); 20041edb306SCy Schubert 20141edb306SCy Schubert return 0; 20241edb306SCy Schubert } 20341edb306SCy Schubert 20441edb306SCy Schubert 205*efeb8bffSCy Schubert int main(int argc, char *argv[]) 20641edb306SCy Schubert { 20741edb306SCy Schubert int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0; 20841edb306SCy Schubert char *dirname = NULL, *filename = NULL, *ifs = NULL; 20941edb306SCy Schubert 21041edb306SCy Schubert progname = argv[0]; 21141edb306SCy Schubert while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1) 21241edb306SCy Schubert switch (c) 21341edb306SCy Schubert { 21441edb306SCy Schubert case 'd' : 21541edb306SCy Schubert if ((set == 0) && !dirname && !filename) 21641edb306SCy Schubert dirname = optarg; 21741edb306SCy Schubert else 21841edb306SCy Schubert usage(); 21941edb306SCy Schubert break; 22041edb306SCy Schubert case 'f' : 22141edb306SCy Schubert if ((set != 0) && !dirname && !filename) 22241edb306SCy Schubert filename = optarg; 22341edb306SCy Schubert else 22441edb306SCy Schubert usage(); 22541edb306SCy Schubert break; 22641edb306SCy Schubert case 'i' : 22741edb306SCy Schubert ifs = optarg; 22841edb306SCy Schubert set = 1; 22941edb306SCy Schubert break; 23041edb306SCy Schubert case 'l' : 23141edb306SCy Schubert if (filename || dirname || set) 23241edb306SCy Schubert usage(); 23341edb306SCy Schubert lock = 1; 23441edb306SCy Schubert set = 1; 23541edb306SCy Schubert break; 23641edb306SCy Schubert case 'n' : 23741edb306SCy Schubert opts |= OPT_DONOTHING; 23841edb306SCy Schubert break; 23941edb306SCy Schubert case 'N' : 24041edb306SCy Schubert if ((ns >= 0) || dirname || (rw != -1) || set) 24141edb306SCy Schubert usage(); 24241edb306SCy Schubert ns = 0; 24341edb306SCy Schubert set = 1; 24441edb306SCy Schubert break; 24541edb306SCy Schubert case 'r' : 24641edb306SCy Schubert if (dirname || (rw != -1) || (ns == -1)) 24741edb306SCy Schubert usage(); 24841edb306SCy Schubert rw = 0; 24941edb306SCy Schubert set = 1; 25041edb306SCy Schubert break; 25141edb306SCy Schubert case 'R' : 25241edb306SCy Schubert rw = 2; 25341edb306SCy Schubert set = 1; 25441edb306SCy Schubert break; 25541edb306SCy Schubert case 'S' : 25641edb306SCy Schubert if ((ns >= 0) || dirname || (rw != -1) || set) 25741edb306SCy Schubert usage(); 25841edb306SCy Schubert ns = 1; 25941edb306SCy Schubert set = 1; 26041edb306SCy Schubert break; 26141edb306SCy Schubert case 'u' : 26241edb306SCy Schubert if (filename || dirname || set) 26341edb306SCy Schubert usage(); 26441edb306SCy Schubert lock = 0; 26541edb306SCy Schubert set = 1; 26641edb306SCy Schubert break; 26741edb306SCy Schubert case 'v' : 26841edb306SCy Schubert opts |= OPT_VERBOSE; 26941edb306SCy Schubert break; 27041edb306SCy Schubert case 'w' : 27141edb306SCy Schubert if (dirname || (rw != -1) || (ns == -1)) 27241edb306SCy Schubert usage(); 27341edb306SCy Schubert rw = 1; 27441edb306SCy Schubert set = 1; 27541edb306SCy Schubert break; 27641edb306SCy Schubert case 'W' : 27741edb306SCy Schubert rw = 3; 27841edb306SCy Schubert set = 1; 27941edb306SCy Schubert break; 28041edb306SCy Schubert case '?' : 28141edb306SCy Schubert default : 28241edb306SCy Schubert usage(); 28341edb306SCy Schubert } 28441edb306SCy Schubert 28541edb306SCy Schubert if (ifs) { 28641edb306SCy Schubert if (!filename || ns < 0) 28741edb306SCy Schubert usage(); 28841edb306SCy Schubert if (ns == 0) 28941edb306SCy Schubert return changenatif(ifs, filename); 29041edb306SCy Schubert else 29141edb306SCy Schubert return changestateif(ifs, filename); 29241edb306SCy Schubert } 29341edb306SCy Schubert 29441edb306SCy Schubert if ((ns >= 0) || (lock >= 0)) { 29541edb306SCy Schubert if (lock >= 0) 29641edb306SCy Schubert devfd = opendevice(NULL); 29741edb306SCy Schubert else if (ns >= 0) { 29841edb306SCy Schubert if (ns == 1) 29941edb306SCy Schubert devfd = opendevice(IPSTATE_NAME); 30041edb306SCy Schubert else if (ns == 0) 30141edb306SCy Schubert devfd = opendevice(IPNAT_NAME); 30241edb306SCy Schubert } 30341edb306SCy Schubert if (devfd == -1) 30441edb306SCy Schubert exit(1); 30541edb306SCy Schubert } 30641edb306SCy Schubert 30741edb306SCy Schubert if (lock >= 0) 30841edb306SCy Schubert err = setlock(devfd, lock); 30941edb306SCy Schubert else if (rw >= 0) { 31041edb306SCy Schubert if (rw & 1) { /* WRITE */ 31141edb306SCy Schubert if (rw & 2) 31241edb306SCy Schubert err = writeall(dirname); 31341edb306SCy Schubert else { 31441edb306SCy Schubert if (ns == 0) 31541edb306SCy Schubert err = writenat(devfd, filename); 31641edb306SCy Schubert else if (ns == 1) 31741edb306SCy Schubert err = writestate(devfd, filename); 31841edb306SCy Schubert } 31941edb306SCy Schubert } else { 32041edb306SCy Schubert if (rw & 2) 32141edb306SCy Schubert err = readall(dirname); 32241edb306SCy Schubert else { 32341edb306SCy Schubert if (ns == 0) 32441edb306SCy Schubert err = readnat(devfd, filename); 32541edb306SCy Schubert else if (ns == 1) 32641edb306SCy Schubert err = readstate(devfd, filename); 32741edb306SCy Schubert } 32841edb306SCy Schubert } 32941edb306SCy Schubert } 33041edb306SCy Schubert return err; 33141edb306SCy Schubert } 33241edb306SCy Schubert 33341edb306SCy Schubert 334*efeb8bffSCy Schubert int opendevice(char *ipfdev) 33541edb306SCy Schubert { 33641edb306SCy Schubert int fd = -1; 33741edb306SCy Schubert 33841edb306SCy Schubert if (opts & OPT_DONOTHING) 33941edb306SCy Schubert return -2; 34041edb306SCy Schubert 34141edb306SCy Schubert if (!ipfdev) 34241edb306SCy Schubert ipfdev = IPL_NAME; 34341edb306SCy Schubert 34441edb306SCy Schubert if ((fd = open(ipfdev, O_RDWR)) == -1) 34541edb306SCy Schubert if ((fd = open(ipfdev, O_RDONLY)) == -1) 34641edb306SCy Schubert perror("open device"); 34741edb306SCy Schubert return fd; 34841edb306SCy Schubert } 34941edb306SCy Schubert 35041edb306SCy Schubert 351*efeb8bffSCy Schubert void closedevice(int fd) 35241edb306SCy Schubert { 35341edb306SCy Schubert close(fd); 35441edb306SCy Schubert } 35541edb306SCy Schubert 35641edb306SCy Schubert 357*efeb8bffSCy Schubert int setlock(int fd, int lock) 35841edb306SCy Schubert { 35941edb306SCy Schubert if (opts & OPT_VERBOSE) 36041edb306SCy Schubert printf("Turn lock %s\n", lock ? "on" : "off"); 36141edb306SCy Schubert if (!(opts & OPT_DONOTHING)) { 36241edb306SCy Schubert if (ioctl(fd, SIOCSTLCK, &lock) == -1) { 36341edb306SCy Schubert perror("SIOCSTLCK"); 36441edb306SCy Schubert return 1; 36541edb306SCy Schubert } 36641edb306SCy Schubert if (opts & OPT_VERBOSE) 36741edb306SCy Schubert printf("Lock now %s\n", lock ? "on" : "off"); 36841edb306SCy Schubert } 36941edb306SCy Schubert return 0; 37041edb306SCy Schubert } 37141edb306SCy Schubert 37241edb306SCy Schubert 373*efeb8bffSCy Schubert int writestate(int fd, char *file) 37441edb306SCy Schubert { 37541edb306SCy Schubert ipstate_save_t ips, *ipsp; 37641edb306SCy Schubert ipfobj_t obj; 37741edb306SCy Schubert int wfd = -1; 37841edb306SCy Schubert 37941edb306SCy Schubert if (!file) 38041edb306SCy Schubert file = IPF_STATEFILE; 38141edb306SCy Schubert 38241edb306SCy Schubert wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); 38341edb306SCy Schubert if (wfd == -1) { 38441edb306SCy Schubert fprintf(stderr, "%s ", file); 38541edb306SCy Schubert perror("state:open"); 38641edb306SCy Schubert return 1; 38741edb306SCy Schubert } 38841edb306SCy Schubert 38941edb306SCy Schubert ipsp = &ips; 39041edb306SCy Schubert bzero((char *)&obj, sizeof(obj)); 39141edb306SCy Schubert bzero((char *)ipsp, sizeof(ips)); 39241edb306SCy Schubert 39341edb306SCy Schubert obj.ipfo_rev = IPFILTER_VERSION; 39441edb306SCy Schubert obj.ipfo_size = sizeof(*ipsp); 39541edb306SCy Schubert obj.ipfo_type = IPFOBJ_STATESAVE; 39641edb306SCy Schubert obj.ipfo_ptr = ipsp; 39741edb306SCy Schubert 39841edb306SCy Schubert do { 39941edb306SCy Schubert 40041edb306SCy Schubert if (opts & OPT_VERBOSE) 40141edb306SCy Schubert printf("Getting state from addr %p\n", ips.ips_next); 40241edb306SCy Schubert if (ioctl(fd, SIOCSTGET, &obj)) { 40341edb306SCy Schubert if (errno == ENOENT) 40441edb306SCy Schubert break; 40541edb306SCy Schubert perror("state:SIOCSTGET"); 40641edb306SCy Schubert close(wfd); 40741edb306SCy Schubert return 1; 40841edb306SCy Schubert } 40941edb306SCy Schubert if (opts & OPT_VERBOSE) 41041edb306SCy Schubert printf("Got state next %p\n", ips.ips_next); 41141edb306SCy Schubert if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) { 41241edb306SCy Schubert perror("state:write"); 41341edb306SCy Schubert close(wfd); 41441edb306SCy Schubert return 1; 41541edb306SCy Schubert } 41641edb306SCy Schubert } while (ips.ips_next != NULL); 41741edb306SCy Schubert close(wfd); 41841edb306SCy Schubert 41941edb306SCy Schubert return 0; 42041edb306SCy Schubert } 42141edb306SCy Schubert 42241edb306SCy Schubert 423*efeb8bffSCy Schubert int readstate(int fd, char *file) 42441edb306SCy Schubert { 42541edb306SCy Schubert ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL; 42641edb306SCy Schubert int sfd = -1, i; 42741edb306SCy Schubert ipfobj_t obj; 42841edb306SCy Schubert 42941edb306SCy Schubert if (!file) 43041edb306SCy Schubert file = IPF_STATEFILE; 43141edb306SCy Schubert 43241edb306SCy Schubert sfd = open(file, O_RDONLY, 0600); 43341edb306SCy Schubert if (sfd == -1) { 43441edb306SCy Schubert fprintf(stderr, "%s ", file); 43541edb306SCy Schubert perror("open"); 43641edb306SCy Schubert return 1; 43741edb306SCy Schubert } 43841edb306SCy Schubert 43941edb306SCy Schubert bzero((char *)&ips, sizeof(ips)); 44041edb306SCy Schubert 44141edb306SCy Schubert /* 44241edb306SCy Schubert * 1. Read all state information in. 44341edb306SCy Schubert */ 44441edb306SCy Schubert do { 44541edb306SCy Schubert i = read(sfd, &ips, sizeof(ips)); 44641edb306SCy Schubert if (i == -1) { 44741edb306SCy Schubert perror("read"); 44841edb306SCy Schubert goto freeipshead; 44941edb306SCy Schubert } 45041edb306SCy Schubert if (i == 0) 45141edb306SCy Schubert break; 45241edb306SCy Schubert if (i != sizeof(ips)) { 45341edb306SCy Schubert fprintf(stderr, "state:incomplete read: %d != %d\n", 45441edb306SCy Schubert i, (int)sizeof(ips)); 45541edb306SCy Schubert goto freeipshead; 45641edb306SCy Schubert } 45741edb306SCy Schubert is = (ipstate_save_t *)malloc(sizeof(*is)); 45841edb306SCy Schubert if (is == NULL) { 45941edb306SCy Schubert fprintf(stderr, "malloc failed\n"); 46041edb306SCy Schubert goto freeipshead; 46141edb306SCy Schubert } 46241edb306SCy Schubert 46341edb306SCy Schubert bcopy((char *)&ips, (char *)is, sizeof(ips)); 46441edb306SCy Schubert 46541edb306SCy Schubert /* 46641edb306SCy Schubert * Check to see if this is the first state entry that will 46741edb306SCy Schubert * reference a particular rule and if so, flag it as such 46841edb306SCy Schubert * else just adjust the rule pointer to become a pointer to 46941edb306SCy Schubert * the other. We do this so we have a means later for tracking 47041edb306SCy Schubert * who is referencing us when we get back the real pointer 47141edb306SCy Schubert * in is_rule after doing the ioctl. 47241edb306SCy Schubert */ 47341edb306SCy Schubert for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next) 47441edb306SCy Schubert if (is1->ips_rule == is->ips_rule) 47541edb306SCy Schubert break; 47641edb306SCy Schubert if (is1 == NULL) 47741edb306SCy Schubert is->ips_is.is_flags |= SI_NEWFR; 47841edb306SCy Schubert else 47941edb306SCy Schubert is->ips_rule = (void *)&is1->ips_rule; 48041edb306SCy Schubert 48141edb306SCy Schubert /* 48241edb306SCy Schubert * Use a tail-queue type list (add things to the end).. 48341edb306SCy Schubert */ 48441edb306SCy Schubert is->ips_next = NULL; 48541edb306SCy Schubert if (!ipshead) 48641edb306SCy Schubert ipshead = is; 48741edb306SCy Schubert if (ipstail) 48841edb306SCy Schubert ipstail->ips_next = is; 48941edb306SCy Schubert ipstail = is; 49041edb306SCy Schubert } while (1); 49141edb306SCy Schubert 49241edb306SCy Schubert close(sfd); 49341edb306SCy Schubert 49441edb306SCy Schubert obj.ipfo_rev = IPFILTER_VERSION; 49541edb306SCy Schubert obj.ipfo_size = sizeof(*is); 49641edb306SCy Schubert obj.ipfo_type = IPFOBJ_STATESAVE; 49741edb306SCy Schubert 49841edb306SCy Schubert while ((is = ipshead) != NULL) { 49941edb306SCy Schubert if (opts & OPT_VERBOSE) 50041edb306SCy Schubert printf("Loading new state table entry\n"); 50141edb306SCy Schubert if (is->ips_is.is_flags & SI_NEWFR) { 50241edb306SCy Schubert if (opts & OPT_VERBOSE) 50341edb306SCy Schubert printf("Loading new filter rule\n"); 50441edb306SCy Schubert } 50541edb306SCy Schubert 50641edb306SCy Schubert obj.ipfo_ptr = is; 50741edb306SCy Schubert if (!(opts & OPT_DONOTHING)) 50841edb306SCy Schubert if (ioctl(fd, SIOCSTPUT, &obj)) { 50941edb306SCy Schubert perror("SIOCSTPUT"); 51041edb306SCy Schubert goto freeipshead; 51141edb306SCy Schubert } 51241edb306SCy Schubert 51341edb306SCy Schubert if (is->ips_is.is_flags & SI_NEWFR) { 51441edb306SCy Schubert if (opts & OPT_VERBOSE) 51541edb306SCy Schubert printf("Real rule addr %p\n", is->ips_rule); 51641edb306SCy Schubert for (is1 = is->ips_next; is1; is1 = is1->ips_next) 51741edb306SCy Schubert if (is1->ips_rule == (frentry_t *)&is->ips_rule) 51841edb306SCy Schubert is1->ips_rule = is->ips_rule; 51941edb306SCy Schubert } 52041edb306SCy Schubert 52141edb306SCy Schubert ipshead = is->ips_next; 52241edb306SCy Schubert free(is); 52341edb306SCy Schubert } 52441edb306SCy Schubert 52541edb306SCy Schubert return 0; 52641edb306SCy Schubert 52741edb306SCy Schubert freeipshead: 52841edb306SCy Schubert while ((is = ipshead) != NULL) { 52941edb306SCy Schubert ipshead = is->ips_next; 53041edb306SCy Schubert free(is); 53141edb306SCy Schubert } 53241edb306SCy Schubert if (sfd != -1) 53341edb306SCy Schubert close(sfd); 53441edb306SCy Schubert return 1; 53541edb306SCy Schubert } 53641edb306SCy Schubert 53741edb306SCy Schubert 538*efeb8bffSCy Schubert int readnat(int fd, char *file) 53941edb306SCy Schubert { 54041edb306SCy Schubert nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL; 54141edb306SCy Schubert ipfobj_t obj; 54241edb306SCy Schubert int nfd, i; 54341edb306SCy Schubert nat_t *nat; 54441edb306SCy Schubert char *s; 54541edb306SCy Schubert int n; 54641edb306SCy Schubert 54741edb306SCy Schubert nfd = -1; 54841edb306SCy Schubert in = NULL; 54941edb306SCy Schubert ipnhead = NULL; 55041edb306SCy Schubert ipntail = NULL; 55141edb306SCy Schubert 55241edb306SCy Schubert if (!file) 55341edb306SCy Schubert file = IPF_NATFILE; 55441edb306SCy Schubert 55541edb306SCy Schubert nfd = open(file, O_RDONLY); 55641edb306SCy Schubert if (nfd == -1) { 55741edb306SCy Schubert fprintf(stderr, "%s ", file); 55841edb306SCy Schubert perror("nat:open"); 55941edb306SCy Schubert return 1; 56041edb306SCy Schubert } 56141edb306SCy Schubert 56241edb306SCy Schubert bzero((char *)&ipn, sizeof(ipn)); 56341edb306SCy Schubert 56441edb306SCy Schubert /* 56541edb306SCy Schubert * 1. Read all state information in. 56641edb306SCy Schubert */ 56741edb306SCy Schubert do { 56841edb306SCy Schubert i = read(nfd, &ipn, sizeof(ipn)); 56941edb306SCy Schubert if (i == -1) { 57041edb306SCy Schubert perror("read"); 57141edb306SCy Schubert goto freenathead; 57241edb306SCy Schubert } 57341edb306SCy Schubert if (i == 0) 57441edb306SCy Schubert break; 57541edb306SCy Schubert if (i != sizeof(ipn)) { 57641edb306SCy Schubert fprintf(stderr, "nat:incomplete read: %d != %d\n", 57741edb306SCy Schubert i, (int)sizeof(ipn)); 57841edb306SCy Schubert goto freenathead; 57941edb306SCy Schubert } 58041edb306SCy Schubert 58141edb306SCy Schubert in = (nat_save_t *)malloc(ipn.ipn_dsize); 58241edb306SCy Schubert if (in == NULL) { 58341edb306SCy Schubert fprintf(stderr, "nat:cannot malloc nat save atruct\n"); 58441edb306SCy Schubert goto freenathead; 58541edb306SCy Schubert } 58641edb306SCy Schubert 58741edb306SCy Schubert if (ipn.ipn_dsize > sizeof(ipn)) { 58841edb306SCy Schubert n = ipn.ipn_dsize - sizeof(ipn); 58941edb306SCy Schubert if (n > 0) { 59041edb306SCy Schubert s = in->ipn_data + sizeof(in->ipn_data); 59141edb306SCy Schubert i = read(nfd, s, n); 59241edb306SCy Schubert if (i == 0) 59341edb306SCy Schubert break; 59441edb306SCy Schubert if (i != n) { 59541edb306SCy Schubert fprintf(stderr, 59641edb306SCy Schubert "nat:incomplete read: %d != %d\n", 59741edb306SCy Schubert i, n); 59841edb306SCy Schubert goto freenathead; 59941edb306SCy Schubert } 60041edb306SCy Schubert } 60141edb306SCy Schubert } 60241edb306SCy Schubert bcopy((char *)&ipn, (char *)in, sizeof(ipn)); 60341edb306SCy Schubert 60441edb306SCy Schubert /* 60541edb306SCy Schubert * Check to see if this is the first NAT entry that will 60641edb306SCy Schubert * reference a particular rule and if so, flag it as such 60741edb306SCy Schubert * else just adjust the rule pointer to become a pointer to 60841edb306SCy Schubert * the other. We do this so we have a means later for tracking 60941edb306SCy Schubert * who is referencing us when we get back the real pointer 61041edb306SCy Schubert * in is_rule after doing the ioctl. 61141edb306SCy Schubert */ 61241edb306SCy Schubert nat = &in->ipn_nat; 61341edb306SCy Schubert if (nat->nat_fr != NULL) { 61441edb306SCy Schubert for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next) 61541edb306SCy Schubert if (in1->ipn_rule == nat->nat_fr) 61641edb306SCy Schubert break; 61741edb306SCy Schubert if (in1 == NULL) 61841edb306SCy Schubert nat->nat_flags |= SI_NEWFR; 61941edb306SCy Schubert else 62041edb306SCy Schubert nat->nat_fr = &in1->ipn_fr; 62141edb306SCy Schubert } 62241edb306SCy Schubert 62341edb306SCy Schubert /* 62441edb306SCy Schubert * Use a tail-queue type list (add things to the end).. 62541edb306SCy Schubert */ 62641edb306SCy Schubert in->ipn_next = NULL; 62741edb306SCy Schubert if (!ipnhead) 62841edb306SCy Schubert ipnhead = in; 62941edb306SCy Schubert if (ipntail) 63041edb306SCy Schubert ipntail->ipn_next = in; 63141edb306SCy Schubert ipntail = in; 63241edb306SCy Schubert } while (1); 63341edb306SCy Schubert 63441edb306SCy Schubert close(nfd); 63541edb306SCy Schubert nfd = -1; 63641edb306SCy Schubert 63741edb306SCy Schubert obj.ipfo_rev = IPFILTER_VERSION; 63841edb306SCy Schubert obj.ipfo_type = IPFOBJ_NATSAVE; 63941edb306SCy Schubert 64041edb306SCy Schubert while ((in = ipnhead) != NULL) { 64141edb306SCy Schubert if (opts & OPT_VERBOSE) 64241edb306SCy Schubert printf("Loading new NAT table entry\n"); 64341edb306SCy Schubert nat = &in->ipn_nat; 64441edb306SCy Schubert if (nat->nat_flags & SI_NEWFR) { 64541edb306SCy Schubert if (opts & OPT_VERBOSE) 64641edb306SCy Schubert printf("Loading new filter rule\n"); 64741edb306SCy Schubert } 64841edb306SCy Schubert 64941edb306SCy Schubert obj.ipfo_ptr = in; 65041edb306SCy Schubert obj.ipfo_size = in->ipn_dsize; 65141edb306SCy Schubert if (!(opts & OPT_DONOTHING)) 65241edb306SCy Schubert if (ioctl(fd, SIOCSTPUT, &obj)) { 65341edb306SCy Schubert fprintf(stderr, "in=%p:", in); 65441edb306SCy Schubert perror("SIOCSTPUT"); 65541edb306SCy Schubert return 1; 65641edb306SCy Schubert } 65741edb306SCy Schubert 65841edb306SCy Schubert if (nat->nat_flags & SI_NEWFR) { 65941edb306SCy Schubert if (opts & OPT_VERBOSE) 66041edb306SCy Schubert printf("Real rule addr %p\n", nat->nat_fr); 66141edb306SCy Schubert for (in1 = in->ipn_next; in1; in1 = in1->ipn_next) 66241edb306SCy Schubert if (in1->ipn_rule == &in->ipn_fr) 66341edb306SCy Schubert in1->ipn_rule = nat->nat_fr; 66441edb306SCy Schubert } 66541edb306SCy Schubert 66641edb306SCy Schubert ipnhead = in->ipn_next; 66741edb306SCy Schubert free(in); 66841edb306SCy Schubert } 66941edb306SCy Schubert 67041edb306SCy Schubert return 0; 67141edb306SCy Schubert 67241edb306SCy Schubert freenathead: 67341edb306SCy Schubert while ((in = ipnhead) != NULL) { 67441edb306SCy Schubert ipnhead = in->ipn_next; 67541edb306SCy Schubert free(in); 67641edb306SCy Schubert } 67741edb306SCy Schubert if (nfd != -1) 67841edb306SCy Schubert close(nfd); 67941edb306SCy Schubert return 1; 68041edb306SCy Schubert } 68141edb306SCy Schubert 68241edb306SCy Schubert 683*efeb8bffSCy Schubert int writenat(int fd, char *file) 68441edb306SCy Schubert { 68541edb306SCy Schubert nat_save_t *ipnp = NULL, *next = NULL; 68641edb306SCy Schubert ipfobj_t obj; 68741edb306SCy Schubert int nfd = -1; 68841edb306SCy Schubert natget_t ng; 68941edb306SCy Schubert 69041edb306SCy Schubert if (!file) 69141edb306SCy Schubert file = IPF_NATFILE; 69241edb306SCy Schubert 69341edb306SCy Schubert nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); 69441edb306SCy Schubert if (nfd == -1) { 69541edb306SCy Schubert fprintf(stderr, "%s ", file); 69641edb306SCy Schubert perror("nat:open"); 69741edb306SCy Schubert return 1; 69841edb306SCy Schubert } 69941edb306SCy Schubert 70041edb306SCy Schubert obj.ipfo_rev = IPFILTER_VERSION; 70141edb306SCy Schubert obj.ipfo_type = IPFOBJ_NATSAVE; 70241edb306SCy Schubert 70341edb306SCy Schubert do { 70441edb306SCy Schubert if (opts & OPT_VERBOSE) 70541edb306SCy Schubert printf("Getting nat from addr %p\n", ipnp); 70641edb306SCy Schubert ng.ng_ptr = next; 70741edb306SCy Schubert ng.ng_sz = 0; 70841edb306SCy Schubert if (ioctl(fd, SIOCSTGSZ, &ng)) { 70941edb306SCy Schubert perror("nat:SIOCSTGSZ"); 71041edb306SCy Schubert close(nfd); 71141edb306SCy Schubert if (ipnp != NULL) 71241edb306SCy Schubert free(ipnp); 71341edb306SCy Schubert return 1; 71441edb306SCy Schubert } 71541edb306SCy Schubert 71641edb306SCy Schubert if (opts & OPT_VERBOSE) 71741edb306SCy Schubert printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr); 71841edb306SCy Schubert 71941edb306SCy Schubert if (ng.ng_sz == 0) 72041edb306SCy Schubert break; 72141edb306SCy Schubert 72241edb306SCy Schubert if (!ipnp) 72341edb306SCy Schubert ipnp = malloc(ng.ng_sz); 72441edb306SCy Schubert else 72541edb306SCy Schubert ipnp = realloc((char *)ipnp, ng.ng_sz); 72641edb306SCy Schubert if (!ipnp) { 72741edb306SCy Schubert fprintf(stderr, 72841edb306SCy Schubert "malloc for %d bytes failed\n", ng.ng_sz); 72941edb306SCy Schubert break; 73041edb306SCy Schubert } 73141edb306SCy Schubert 73241edb306SCy Schubert bzero((char *)ipnp, ng.ng_sz); 73341edb306SCy Schubert obj.ipfo_size = ng.ng_sz; 73441edb306SCy Schubert obj.ipfo_ptr = ipnp; 73541edb306SCy Schubert ipnp->ipn_dsize = ng.ng_sz; 73641edb306SCy Schubert ipnp->ipn_next = next; 73741edb306SCy Schubert if (ioctl(fd, SIOCSTGET, &obj)) { 73841edb306SCy Schubert if (errno == ENOENT) 73941edb306SCy Schubert break; 74041edb306SCy Schubert perror("nat:SIOCSTGET"); 74141edb306SCy Schubert close(nfd); 74241edb306SCy Schubert free(ipnp); 74341edb306SCy Schubert return 1; 74441edb306SCy Schubert } 74541edb306SCy Schubert 74641edb306SCy Schubert if (opts & OPT_VERBOSE) 74741edb306SCy Schubert printf("Got nat next %p ipn_dsize %d ng_sz %d\n", 74841edb306SCy Schubert ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz); 74941edb306SCy Schubert if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) { 75041edb306SCy Schubert perror("nat:write"); 75141edb306SCy Schubert close(nfd); 75241edb306SCy Schubert free(ipnp); 75341edb306SCy Schubert return 1; 75441edb306SCy Schubert } 75541edb306SCy Schubert next = ipnp->ipn_next; 75641edb306SCy Schubert } while (ipnp && next); 75741edb306SCy Schubert if (ipnp != NULL) 75841edb306SCy Schubert free(ipnp); 75941edb306SCy Schubert close(nfd); 76041edb306SCy Schubert 76141edb306SCy Schubert return 0; 76241edb306SCy Schubert } 76341edb306SCy Schubert 76441edb306SCy Schubert 765*efeb8bffSCy Schubert int writeall(char *dirname) 76641edb306SCy Schubert { 76741edb306SCy Schubert int fd, devfd; 76841edb306SCy Schubert 76941edb306SCy Schubert if (!dirname) 77041edb306SCy Schubert dirname = IPF_SAVEDIR; 77141edb306SCy Schubert 77241edb306SCy Schubert if (chdir(dirname)) { 77341edb306SCy Schubert fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname); 77441edb306SCy Schubert perror("chdir(IPF_SAVEDIR)"); 77541edb306SCy Schubert return 1; 77641edb306SCy Schubert } 77741edb306SCy Schubert 77841edb306SCy Schubert fd = opendevice(NULL); 77941edb306SCy Schubert if (fd == -1) 78041edb306SCy Schubert return 1; 78141edb306SCy Schubert if (setlock(fd, 1)) { 78241edb306SCy Schubert close(fd); 78341edb306SCy Schubert return 1; 78441edb306SCy Schubert } 78541edb306SCy Schubert 78641edb306SCy Schubert devfd = opendevice(IPSTATE_NAME); 78741edb306SCy Schubert if (devfd == -1) 78841edb306SCy Schubert goto bad; 78941edb306SCy Schubert if (writestate(devfd, NULL)) 79041edb306SCy Schubert goto bad; 79141edb306SCy Schubert close(devfd); 79241edb306SCy Schubert 79341edb306SCy Schubert devfd = opendevice(IPNAT_NAME); 79441edb306SCy Schubert if (devfd == -1) 79541edb306SCy Schubert goto bad; 79641edb306SCy Schubert if (writenat(devfd, NULL)) 79741edb306SCy Schubert goto bad; 79841edb306SCy Schubert close(devfd); 79941edb306SCy Schubert 80041edb306SCy Schubert if (setlock(fd, 0)) { 80141edb306SCy Schubert close(fd); 80241edb306SCy Schubert return 1; 80341edb306SCy Schubert } 80441edb306SCy Schubert 80541edb306SCy Schubert close(fd); 80641edb306SCy Schubert return 0; 80741edb306SCy Schubert 80841edb306SCy Schubert bad: 80941edb306SCy Schubert setlock(fd, 0); 81041edb306SCy Schubert close(fd); 81141edb306SCy Schubert return 1; 81241edb306SCy Schubert } 81341edb306SCy Schubert 81441edb306SCy Schubert 815*efeb8bffSCy Schubert int readall(char *dirname) 81641edb306SCy Schubert { 81741edb306SCy Schubert int fd, devfd; 81841edb306SCy Schubert 81941edb306SCy Schubert if (!dirname) 82041edb306SCy Schubert dirname = IPF_SAVEDIR; 82141edb306SCy Schubert 82241edb306SCy Schubert if (chdir(dirname)) { 82341edb306SCy Schubert perror("chdir(IPF_SAVEDIR)"); 82441edb306SCy Schubert return 1; 82541edb306SCy Schubert } 82641edb306SCy Schubert 82741edb306SCy Schubert fd = opendevice(NULL); 82841edb306SCy Schubert if (fd == -1) 82941edb306SCy Schubert return 1; 83041edb306SCy Schubert if (setlock(fd, 1)) { 83141edb306SCy Schubert close(fd); 83241edb306SCy Schubert return 1; 83341edb306SCy Schubert } 83441edb306SCy Schubert 83541edb306SCy Schubert devfd = opendevice(IPSTATE_NAME); 83641edb306SCy Schubert if (devfd == -1) 83741edb306SCy Schubert return 1; 83841edb306SCy Schubert if (readstate(devfd, NULL)) 83941edb306SCy Schubert return 1; 84041edb306SCy Schubert close(devfd); 84141edb306SCy Schubert 84241edb306SCy Schubert devfd = opendevice(IPNAT_NAME); 84341edb306SCy Schubert if (devfd == -1) 84441edb306SCy Schubert return 1; 84541edb306SCy Schubert if (readnat(devfd, NULL)) 84641edb306SCy Schubert return 1; 84741edb306SCy Schubert close(devfd); 84841edb306SCy Schubert 84941edb306SCy Schubert if (setlock(fd, 0)) { 85041edb306SCy Schubert close(fd); 85141edb306SCy Schubert return 1; 85241edb306SCy Schubert } 85341edb306SCy Schubert 85441edb306SCy Schubert return 0; 85541edb306SCy Schubert } 856