10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * Copyright (C) 1999-2001, 2003 by Darren Reed. 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * See the IPFILTER.LICENCE file for details on licencing. 50Sstevel@tonic-gate * 6*2393Syz155240 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 70Sstevel@tonic-gate * Use is subject to license terms. 80Sstevel@tonic-gate */ 90Sstevel@tonic-gate 100Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 110Sstevel@tonic-gate 120Sstevel@tonic-gate #ifdef __FreeBSD__ 130Sstevel@tonic-gate # ifndef __FreeBSD_cc_version 140Sstevel@tonic-gate # include <osreldate.h> 150Sstevel@tonic-gate # else 160Sstevel@tonic-gate # if __FreeBSD_cc_version < 430000 170Sstevel@tonic-gate # include <osreldate.h> 180Sstevel@tonic-gate # endif 190Sstevel@tonic-gate # endif 200Sstevel@tonic-gate #endif 210Sstevel@tonic-gate #include <stdio.h> 220Sstevel@tonic-gate #include <unistd.h> 230Sstevel@tonic-gate #include <string.h> 240Sstevel@tonic-gate #include <fcntl.h> 250Sstevel@tonic-gate #include <errno.h> 260Sstevel@tonic-gate #if !defined(__SVR4) && !defined(__GNUC__) 270Sstevel@tonic-gate #include <strings.h> 280Sstevel@tonic-gate #endif 290Sstevel@tonic-gate #include <sys/types.h> 300Sstevel@tonic-gate #include <sys/param.h> 310Sstevel@tonic-gate #include <sys/file.h> 320Sstevel@tonic-gate #include <stdlib.h> 330Sstevel@tonic-gate #include <stddef.h> 340Sstevel@tonic-gate #include <sys/socket.h> 350Sstevel@tonic-gate #include <sys/ioctl.h> 360Sstevel@tonic-gate #include <netinet/in.h> 370Sstevel@tonic-gate #include <netinet/in_systm.h> 380Sstevel@tonic-gate #include <sys/time.h> 390Sstevel@tonic-gate #include <net/if.h> 400Sstevel@tonic-gate #if __FreeBSD_version >= 300000 410Sstevel@tonic-gate # include <net/if_var.h> 420Sstevel@tonic-gate #endif 430Sstevel@tonic-gate #include <netinet/ip.h> 440Sstevel@tonic-gate #include <netdb.h> 450Sstevel@tonic-gate #include <arpa/nameser.h> 460Sstevel@tonic-gate #include <resolv.h> 470Sstevel@tonic-gate #include "ipf.h" 48*2393Syz155240 #include "netinet/ipl.h" 490Sstevel@tonic-gate 500Sstevel@tonic-gate #if !defined(lint) 51*2393Syz155240 static const char rcsid[] = "@(#)Id: ipfs.c,v 1.12 2003/12/01 01:56:53 darrenr Exp"; 520Sstevel@tonic-gate #endif 530Sstevel@tonic-gate 540Sstevel@tonic-gate #ifndef IPF_SAVEDIR 550Sstevel@tonic-gate # define IPF_SAVEDIR "/var/db/ipf" 560Sstevel@tonic-gate #endif 570Sstevel@tonic-gate #ifndef IPF_NATFILE 580Sstevel@tonic-gate # define IPF_NATFILE "ipnat.ipf" 590Sstevel@tonic-gate #endif 600Sstevel@tonic-gate #ifndef IPF_STATEFILE 610Sstevel@tonic-gate # define IPF_STATEFILE "ipstate.ipf" 620Sstevel@tonic-gate #endif 630Sstevel@tonic-gate 640Sstevel@tonic-gate #if !defined(__SVR4) && defined(__GNUC__) 650Sstevel@tonic-gate extern char *index __P((const char *, int)); 660Sstevel@tonic-gate #endif 670Sstevel@tonic-gate 680Sstevel@tonic-gate extern char *optarg; 690Sstevel@tonic-gate extern int optind; 700Sstevel@tonic-gate 710Sstevel@tonic-gate int main __P((int, char *[])); 720Sstevel@tonic-gate void usage __P((void)); 730Sstevel@tonic-gate int changestateif __P((char *, char *)); 740Sstevel@tonic-gate int changenatif __P((char *, char *)); 750Sstevel@tonic-gate int readstate __P((int, char *)); 760Sstevel@tonic-gate int readnat __P((int, char *)); 770Sstevel@tonic-gate int writestate __P((int, char *)); 780Sstevel@tonic-gate int opendevice __P((char *)); 790Sstevel@tonic-gate void closedevice __P((int)); 800Sstevel@tonic-gate int setlock __P((int, int)); 810Sstevel@tonic-gate int writeall __P((char *)); 820Sstevel@tonic-gate int readall __P((char *)); 830Sstevel@tonic-gate int writenat __P((int, char *)); 840Sstevel@tonic-gate 850Sstevel@tonic-gate int opts = 0; 860Sstevel@tonic-gate char *progname; 870Sstevel@tonic-gate 880Sstevel@tonic-gate 890Sstevel@tonic-gate void usage() 900Sstevel@tonic-gate { 910Sstevel@tonic-gate fprintf(stderr, "usage: %s [-nv] -l\n", progname); 920Sstevel@tonic-gate fprintf(stderr, "usage: %s [-nv] -u\n", progname); 930Sstevel@tonic-gate fprintf(stderr, "usage: %s [-nv] [-d <dir>] -R\n", progname); 940Sstevel@tonic-gate fprintf(stderr, "usage: %s [-nv] [-d <dir>] -W\n", progname); 950Sstevel@tonic-gate fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -r\n", progname); 960Sstevel@tonic-gate fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -w\n", progname); 970Sstevel@tonic-gate fprintf(stderr, "usage: %s [-nNSv] -f <filename> -i <if1>,<if2>\n", 980Sstevel@tonic-gate progname); 990Sstevel@tonic-gate exit(1); 1000Sstevel@tonic-gate } 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate /* 1040Sstevel@tonic-gate * Change interface names in state information saved out to disk. 1050Sstevel@tonic-gate */ 1060Sstevel@tonic-gate int changestateif(ifs, fname) 1070Sstevel@tonic-gate char *ifs, *fname; 1080Sstevel@tonic-gate { 1090Sstevel@tonic-gate int fd, olen, nlen, rw; 1100Sstevel@tonic-gate ipstate_save_t ips; 1110Sstevel@tonic-gate off_t pos; 1120Sstevel@tonic-gate char *s; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate s = strchr(ifs, ','); 1150Sstevel@tonic-gate if (!s) 1160Sstevel@tonic-gate usage(); 1170Sstevel@tonic-gate *s++ = '\0'; 1180Sstevel@tonic-gate nlen = strlen(s); 1190Sstevel@tonic-gate olen = strlen(ifs); 1200Sstevel@tonic-gate if (nlen >= sizeof(ips.ips_is.is_ifname) || 1210Sstevel@tonic-gate olen >= sizeof(ips.ips_is.is_ifname)) 1220Sstevel@tonic-gate usage(); 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate fd = open(fname, O_RDWR); 1250Sstevel@tonic-gate if (fd == -1) { 1260Sstevel@tonic-gate perror("open"); 1270Sstevel@tonic-gate exit(1); 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) { 1310Sstevel@tonic-gate rw = 0; 1320Sstevel@tonic-gate if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) { 1330Sstevel@tonic-gate strcpy(ips.ips_is.is_ifname[0], s); 1340Sstevel@tonic-gate rw = 1; 1350Sstevel@tonic-gate } 1360Sstevel@tonic-gate if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) { 1370Sstevel@tonic-gate strcpy(ips.ips_is.is_ifname[1], s); 1380Sstevel@tonic-gate rw = 1; 1390Sstevel@tonic-gate } 1400Sstevel@tonic-gate if (rw == 1) { 1410Sstevel@tonic-gate if (lseek(fd, pos, SEEK_SET) != pos) { 1420Sstevel@tonic-gate perror("lseek"); 1430Sstevel@tonic-gate exit(1); 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) { 1460Sstevel@tonic-gate perror("write"); 1470Sstevel@tonic-gate exit(1); 1480Sstevel@tonic-gate } 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate pos = lseek(fd, 0, SEEK_CUR); 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate close(fd); 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate return 0; 1550Sstevel@tonic-gate } 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate /* 1590Sstevel@tonic-gate * Change interface names in NAT information saved out to disk. 1600Sstevel@tonic-gate */ 1610Sstevel@tonic-gate int changenatif(ifs, fname) 1620Sstevel@tonic-gate char *ifs, *fname; 1630Sstevel@tonic-gate { 1640Sstevel@tonic-gate int fd, olen, nlen, rw; 1650Sstevel@tonic-gate nat_save_t ipn; 1660Sstevel@tonic-gate nat_t *nat; 1670Sstevel@tonic-gate off_t pos; 1680Sstevel@tonic-gate char *s; 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate s = strchr(ifs, ','); 1710Sstevel@tonic-gate if (!s) 1720Sstevel@tonic-gate usage(); 1730Sstevel@tonic-gate *s++ = '\0'; 1740Sstevel@tonic-gate nlen = strlen(s); 1750Sstevel@tonic-gate olen = strlen(ifs); 1760Sstevel@tonic-gate nat = &ipn.ipn_nat; 1770Sstevel@tonic-gate if (nlen >= sizeof(nat->nat_ifnames[0]) || 1780Sstevel@tonic-gate olen >= sizeof(nat->nat_ifnames[0])) 1790Sstevel@tonic-gate usage(); 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate fd = open(fname, O_RDWR); 1820Sstevel@tonic-gate if (fd == -1) { 1830Sstevel@tonic-gate perror("open"); 1840Sstevel@tonic-gate exit(1); 1850Sstevel@tonic-gate } 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) { 1880Sstevel@tonic-gate rw = 0; 1890Sstevel@tonic-gate if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) { 1900Sstevel@tonic-gate strcpy(nat->nat_ifnames[0], s); 1910Sstevel@tonic-gate rw = 1; 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) { 1940Sstevel@tonic-gate strcpy(nat->nat_ifnames[1], s); 1950Sstevel@tonic-gate rw = 1; 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate if (rw == 1) { 1980Sstevel@tonic-gate if (lseek(fd, pos, SEEK_SET) != pos) { 1990Sstevel@tonic-gate perror("lseek"); 2000Sstevel@tonic-gate exit(1); 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) { 2030Sstevel@tonic-gate perror("write"); 2040Sstevel@tonic-gate exit(1); 2050Sstevel@tonic-gate } 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate pos = lseek(fd, 0, SEEK_CUR); 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate close(fd); 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate return 0; 2120Sstevel@tonic-gate } 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate int main(argc,argv) 2160Sstevel@tonic-gate int argc; 2170Sstevel@tonic-gate char *argv[]; 2180Sstevel@tonic-gate { 2190Sstevel@tonic-gate int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0; 2200Sstevel@tonic-gate char *dirname = NULL, *filename = NULL, *ifs = NULL; 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate progname = argv[0]; 2230Sstevel@tonic-gate while ((c = getopt(argc, argv, "d:f:lNnSRruvWw")) != -1) 2240Sstevel@tonic-gate switch (c) 2250Sstevel@tonic-gate { 2260Sstevel@tonic-gate case 'd' : 2270Sstevel@tonic-gate if ((set == 0) && !dirname && !filename) 2280Sstevel@tonic-gate dirname = optarg; 2290Sstevel@tonic-gate else 2300Sstevel@tonic-gate usage(); 2310Sstevel@tonic-gate break; 2320Sstevel@tonic-gate case 'f' : 2330Sstevel@tonic-gate if ((set == 0) && !dirname && !filename) 2340Sstevel@tonic-gate filename = optarg; 2350Sstevel@tonic-gate else 2360Sstevel@tonic-gate usage(); 2370Sstevel@tonic-gate break; 2380Sstevel@tonic-gate case 'i' : 2390Sstevel@tonic-gate ifs = optarg; 2400Sstevel@tonic-gate set = 1; 2410Sstevel@tonic-gate break; 2420Sstevel@tonic-gate case 'l' : 2430Sstevel@tonic-gate if (filename || dirname || set) 2440Sstevel@tonic-gate usage(); 2450Sstevel@tonic-gate lock = 1; 2460Sstevel@tonic-gate set = 1; 2470Sstevel@tonic-gate break; 2480Sstevel@tonic-gate case 'n' : 2490Sstevel@tonic-gate opts |= OPT_DONOTHING; 2500Sstevel@tonic-gate break; 2510Sstevel@tonic-gate case 'N' : 2520Sstevel@tonic-gate if ((ns >= 0) || dirname || (rw != -1) || set) 2530Sstevel@tonic-gate usage(); 2540Sstevel@tonic-gate ns = 0; 2550Sstevel@tonic-gate set = 1; 2560Sstevel@tonic-gate break; 2570Sstevel@tonic-gate case 'r' : 258*2393Syz155240 if (dirname || (rw != -1) || (ns == -1)) 2590Sstevel@tonic-gate usage(); 2600Sstevel@tonic-gate rw = 0; 2610Sstevel@tonic-gate set = 1; 2620Sstevel@tonic-gate break; 2630Sstevel@tonic-gate case 'R' : 2640Sstevel@tonic-gate rw = 2; 2650Sstevel@tonic-gate set = 1; 2660Sstevel@tonic-gate break; 2670Sstevel@tonic-gate case 'S' : 2680Sstevel@tonic-gate if ((ns >= 0) || dirname || (rw != -1) || set) 2690Sstevel@tonic-gate usage(); 2700Sstevel@tonic-gate ns = 1; 2710Sstevel@tonic-gate set = 1; 2720Sstevel@tonic-gate break; 2730Sstevel@tonic-gate case 'u' : 2740Sstevel@tonic-gate if (filename || dirname || set) 2750Sstevel@tonic-gate usage(); 2760Sstevel@tonic-gate lock = 0; 2770Sstevel@tonic-gate set = 1; 2780Sstevel@tonic-gate break; 2790Sstevel@tonic-gate case 'v' : 2800Sstevel@tonic-gate opts |= OPT_VERBOSE; 2810Sstevel@tonic-gate break; 2820Sstevel@tonic-gate case 'w' : 2830Sstevel@tonic-gate if (dirname || (rw != -1) || (ns == -1)) 2840Sstevel@tonic-gate usage(); 2850Sstevel@tonic-gate rw = 1; 2860Sstevel@tonic-gate set = 1; 2870Sstevel@tonic-gate break; 2880Sstevel@tonic-gate case 'W' : 2890Sstevel@tonic-gate rw = 3; 2900Sstevel@tonic-gate set = 1; 2910Sstevel@tonic-gate break; 2920Sstevel@tonic-gate case '?' : 2930Sstevel@tonic-gate default : 2940Sstevel@tonic-gate usage(); 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate if (ifs) { 2980Sstevel@tonic-gate if (!filename || ns < 0) 2990Sstevel@tonic-gate usage(); 3000Sstevel@tonic-gate if (ns == 0) 3010Sstevel@tonic-gate return changenatif(ifs, filename); 3020Sstevel@tonic-gate else 3030Sstevel@tonic-gate return changestateif(ifs, filename); 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate if ((ns >= 0) || (lock >= 0)) { 3070Sstevel@tonic-gate if (lock >= 0) 3080Sstevel@tonic-gate devfd = opendevice(NULL); 3090Sstevel@tonic-gate else if (ns >= 0) { 3100Sstevel@tonic-gate if (ns == 1) 3110Sstevel@tonic-gate devfd = opendevice(IPSTATE_NAME); 3120Sstevel@tonic-gate else if (ns == 0) 3130Sstevel@tonic-gate devfd = opendevice(IPNAT_NAME); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate if (devfd == -1) 3160Sstevel@tonic-gate exit(1); 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate if (lock >= 0) 3200Sstevel@tonic-gate err = setlock(devfd, lock); 3210Sstevel@tonic-gate else if (rw >= 0) { 3220Sstevel@tonic-gate if (rw & 1) { /* WRITE */ 3230Sstevel@tonic-gate if (rw & 2) 3240Sstevel@tonic-gate err = writeall(dirname); 3250Sstevel@tonic-gate else { 3260Sstevel@tonic-gate if (ns == 0) 3270Sstevel@tonic-gate err = writenat(devfd, filename); 3280Sstevel@tonic-gate else if (ns == 1) 3290Sstevel@tonic-gate err = writestate(devfd, filename); 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate } else { 3320Sstevel@tonic-gate if (rw & 2) 3330Sstevel@tonic-gate err = readall(dirname); 3340Sstevel@tonic-gate else { 3350Sstevel@tonic-gate if (ns == 0) 3360Sstevel@tonic-gate err = readnat(devfd, filename); 3370Sstevel@tonic-gate else if (ns == 1) 3380Sstevel@tonic-gate err = readstate(devfd, filename); 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate return err; 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate int opendevice(ipfdev) 3470Sstevel@tonic-gate char *ipfdev; 3480Sstevel@tonic-gate { 3490Sstevel@tonic-gate int fd = -1; 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate if (opts & OPT_DONOTHING) 3520Sstevel@tonic-gate return -2; 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate if (!ipfdev) 3550Sstevel@tonic-gate ipfdev = IPL_NAME; 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate if ((fd = open(ipfdev, O_RDWR)) == -1) 3580Sstevel@tonic-gate if ((fd = open(ipfdev, O_RDONLY)) == -1) 3590Sstevel@tonic-gate perror("open device"); 3600Sstevel@tonic-gate return fd; 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate void closedevice(fd) 3650Sstevel@tonic-gate int fd; 3660Sstevel@tonic-gate { 3670Sstevel@tonic-gate close(fd); 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate int setlock(fd, lock) 3720Sstevel@tonic-gate int fd, lock; 3730Sstevel@tonic-gate { 3740Sstevel@tonic-gate if (opts & OPT_VERBOSE) 3750Sstevel@tonic-gate printf("Turn lock %s\n", lock ? "on" : "off"); 3760Sstevel@tonic-gate if (!(opts & OPT_DONOTHING)) { 3770Sstevel@tonic-gate if (ioctl(fd, SIOCSTLCK, &lock) == -1) { 3780Sstevel@tonic-gate perror("SIOCSTLCK"); 3790Sstevel@tonic-gate return 1; 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate if (opts & OPT_VERBOSE) 3820Sstevel@tonic-gate printf("Lock now %s\n", lock ? "on" : "off"); 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate return 0; 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate int writestate(fd, file) 3890Sstevel@tonic-gate int fd; 3900Sstevel@tonic-gate char *file; 3910Sstevel@tonic-gate { 3920Sstevel@tonic-gate ipstate_save_t ips, *ipsp; 393*2393Syz155240 ipfobj_t obj; 3940Sstevel@tonic-gate int wfd = -1; 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate if (!file) 3970Sstevel@tonic-gate file = IPF_STATEFILE; 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); 4000Sstevel@tonic-gate if (wfd == -1) { 4010Sstevel@tonic-gate fprintf(stderr, "%s ", file); 4020Sstevel@tonic-gate perror("state:open"); 4030Sstevel@tonic-gate return 1; 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate ipsp = &ips; 407*2393Syz155240 bzero((char *)&obj, sizeof(obj)); 4080Sstevel@tonic-gate bzero((char *)ipsp, sizeof(ips)); 4090Sstevel@tonic-gate 410*2393Syz155240 obj.ipfo_rev = IPFILTER_VERSION; 411*2393Syz155240 obj.ipfo_size = sizeof(*ipsp); 412*2393Syz155240 obj.ipfo_type = IPFOBJ_STATESAVE; 413*2393Syz155240 obj.ipfo_ptr = ipsp; 414*2393Syz155240 4150Sstevel@tonic-gate do { 416*2393Syz155240 4170Sstevel@tonic-gate if (opts & OPT_VERBOSE) 4180Sstevel@tonic-gate printf("Getting state from addr %p\n", ips.ips_next); 419*2393Syz155240 if (ioctl(fd, SIOCSTGET, &obj)) { 4200Sstevel@tonic-gate if (errno == ENOENT) 4210Sstevel@tonic-gate break; 4220Sstevel@tonic-gate perror("state:SIOCSTGET"); 4230Sstevel@tonic-gate close(wfd); 4240Sstevel@tonic-gate return 1; 4250Sstevel@tonic-gate } 4260Sstevel@tonic-gate if (opts & OPT_VERBOSE) 4270Sstevel@tonic-gate printf("Got state next %p\n", ips.ips_next); 4280Sstevel@tonic-gate if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) { 4290Sstevel@tonic-gate perror("state:write"); 4300Sstevel@tonic-gate close(wfd); 4310Sstevel@tonic-gate return 1; 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate } while (ips.ips_next != NULL); 4340Sstevel@tonic-gate close(wfd); 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate return 0; 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate int readstate(fd, file) 4410Sstevel@tonic-gate int fd; 4420Sstevel@tonic-gate char *file; 4430Sstevel@tonic-gate { 4440Sstevel@tonic-gate ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL; 4450Sstevel@tonic-gate int sfd = -1, i; 446*2393Syz155240 ipfobj_t obj; 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate if (!file) 4490Sstevel@tonic-gate file = IPF_STATEFILE; 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate sfd = open(file, O_RDONLY, 0600); 4520Sstevel@tonic-gate if (sfd == -1) { 4530Sstevel@tonic-gate fprintf(stderr, "%s ", file); 4540Sstevel@tonic-gate perror("open"); 4550Sstevel@tonic-gate return 1; 4560Sstevel@tonic-gate } 4570Sstevel@tonic-gate 4580Sstevel@tonic-gate bzero((char *)&ips, sizeof(ips)); 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate /* 4610Sstevel@tonic-gate * 1. Read all state information in. 4620Sstevel@tonic-gate */ 4630Sstevel@tonic-gate do { 4640Sstevel@tonic-gate i = read(sfd, &ips, sizeof(ips)); 4650Sstevel@tonic-gate if (i == -1) { 4660Sstevel@tonic-gate perror("read"); 4670Sstevel@tonic-gate close(sfd); 4680Sstevel@tonic-gate return 1; 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate if (i == 0) 4710Sstevel@tonic-gate break; 4720Sstevel@tonic-gate if (i != sizeof(ips)) { 473*2393Syz155240 fprintf(stderr, "state:incomplete read: %d != %d\n", 474*2393Syz155240 i, (int)sizeof(ips)); 4750Sstevel@tonic-gate close(sfd); 4760Sstevel@tonic-gate return 1; 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate is = (ipstate_save_t *)malloc(sizeof(*is)); 4790Sstevel@tonic-gate if(!is) { 4800Sstevel@tonic-gate fprintf(stderr, "malloc failed\n"); 4810Sstevel@tonic-gate return 1; 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate bcopy((char *)&ips, (char *)is, sizeof(ips)); 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate /* 4870Sstevel@tonic-gate * Check to see if this is the first state entry that will 4880Sstevel@tonic-gate * reference a particular rule and if so, flag it as such 4890Sstevel@tonic-gate * else just adjust the rule pointer to become a pointer to 4900Sstevel@tonic-gate * the other. We do this so we have a means later for tracking 4910Sstevel@tonic-gate * who is referencing us when we get back the real pointer 4920Sstevel@tonic-gate * in is_rule after doing the ioctl. 4930Sstevel@tonic-gate */ 4940Sstevel@tonic-gate for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next) 4950Sstevel@tonic-gate if (is1->ips_rule == is->ips_rule) 4960Sstevel@tonic-gate break; 4970Sstevel@tonic-gate if (is1 == NULL) 4980Sstevel@tonic-gate is->ips_is.is_flags |= SI_NEWFR; 4990Sstevel@tonic-gate else 5000Sstevel@tonic-gate is->ips_rule = (void *)&is1->ips_rule; 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate /* 5030Sstevel@tonic-gate * Use a tail-queue type list (add things to the end).. 5040Sstevel@tonic-gate */ 5050Sstevel@tonic-gate is->ips_next = NULL; 5060Sstevel@tonic-gate if (!ipshead) 5070Sstevel@tonic-gate ipshead = is; 5080Sstevel@tonic-gate if (ipstail) 5090Sstevel@tonic-gate ipstail->ips_next = is; 5100Sstevel@tonic-gate ipstail = is; 5110Sstevel@tonic-gate } while (1); 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate close(sfd); 5140Sstevel@tonic-gate 515*2393Syz155240 obj.ipfo_rev = IPFILTER_VERSION; 516*2393Syz155240 obj.ipfo_size = sizeof(*is); 517*2393Syz155240 obj.ipfo_type = IPFOBJ_STATESAVE; 518*2393Syz155240 5190Sstevel@tonic-gate for (is = ipshead; is; is = is->ips_next) { 5200Sstevel@tonic-gate if (opts & OPT_VERBOSE) 5210Sstevel@tonic-gate printf("Loading new state table entry\n"); 5220Sstevel@tonic-gate if (is->ips_is.is_flags & SI_NEWFR) { 5230Sstevel@tonic-gate if (opts & OPT_VERBOSE) 5240Sstevel@tonic-gate printf("Loading new filter rule\n"); 5250Sstevel@tonic-gate } 526*2393Syz155240 527*2393Syz155240 obj.ipfo_ptr = is; 5280Sstevel@tonic-gate if (!(opts & OPT_DONOTHING)) 529*2393Syz155240 if (ioctl(fd, SIOCSTPUT, &obj)) { 5300Sstevel@tonic-gate perror("SIOCSTPUT"); 5310Sstevel@tonic-gate return 1; 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate if (is->ips_is.is_flags & SI_NEWFR) { 5350Sstevel@tonic-gate if (opts & OPT_VERBOSE) 5360Sstevel@tonic-gate printf("Real rule addr %p\n", is->ips_rule); 5370Sstevel@tonic-gate for (is1 = is->ips_next; is1; is1 = is1->ips_next) 5380Sstevel@tonic-gate if (is1->ips_rule == (frentry_t *)&is->ips_rule) 5390Sstevel@tonic-gate is1->ips_rule = is->ips_rule; 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate return 0; 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate int readnat(fd, file) 5480Sstevel@tonic-gate int fd; 5490Sstevel@tonic-gate char *file; 5500Sstevel@tonic-gate { 551*2393Syz155240 nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL; 552*2393Syz155240 ipfobj_t obj; 5530Sstevel@tonic-gate int nfd, i; 5540Sstevel@tonic-gate nat_t *nat; 555*2393Syz155240 char *s; 556*2393Syz155240 int n; 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate nfd = -1; 5590Sstevel@tonic-gate in = NULL; 5600Sstevel@tonic-gate ipnhead = NULL; 5610Sstevel@tonic-gate ipntail = NULL; 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate if (!file) 5640Sstevel@tonic-gate file = IPF_NATFILE; 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate nfd = open(file, O_RDONLY); 5670Sstevel@tonic-gate if (nfd == -1) { 5680Sstevel@tonic-gate fprintf(stderr, "%s ", file); 5690Sstevel@tonic-gate perror("nat:open"); 5700Sstevel@tonic-gate return 1; 5710Sstevel@tonic-gate } 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate bzero((char *)&ipn, sizeof(ipn)); 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate /* 5760Sstevel@tonic-gate * 1. Read all state information in. 5770Sstevel@tonic-gate */ 5780Sstevel@tonic-gate do { 5790Sstevel@tonic-gate i = read(nfd, &ipn, sizeof(ipn)); 5800Sstevel@tonic-gate if (i == -1) { 5810Sstevel@tonic-gate perror("read"); 5820Sstevel@tonic-gate close(nfd); 5830Sstevel@tonic-gate return 1; 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate if (i == 0) 5860Sstevel@tonic-gate break; 5870Sstevel@tonic-gate if (i != sizeof(ipn)) { 588*2393Syz155240 fprintf(stderr, "nat:incomplete read: %d != %d\n", 589*2393Syz155240 i, (int)sizeof(ipn)); 5900Sstevel@tonic-gate close(nfd); 5910Sstevel@tonic-gate return 1; 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate 594*2393Syz155240 in = (nat_save_t *)malloc(ipn.ipn_dsize); 595*2393Syz155240 if (!in) 596*2393Syz155240 break; 5970Sstevel@tonic-gate 598*2393Syz155240 if (ipn.ipn_dsize > sizeof(ipn)) { 599*2393Syz155240 n = ipn.ipn_dsize - sizeof(ipn); 600*2393Syz155240 if (n > 0) { 601*2393Syz155240 s = in->ipn_data + sizeof(in->ipn_data); 602*2393Syz155240 i = read(nfd, s, n); 603*2393Syz155240 if (i == 0) 604*2393Syz155240 break; 605*2393Syz155240 if (i != n) { 606*2393Syz155240 fprintf(stderr, 607*2393Syz155240 "nat:incomplete read: %d != %d\n", 608*2393Syz155240 i, n); 609*2393Syz155240 close(nfd); 610*2393Syz155240 return 1; 611*2393Syz155240 } 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate } 614*2393Syz155240 bcopy((char *)&ipn, (char *)in, sizeof(ipn)); 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate /* 617*2393Syz155240 * Check to see if this is the first NAT entry that will 6180Sstevel@tonic-gate * reference a particular rule and if so, flag it as such 6190Sstevel@tonic-gate * else just adjust the rule pointer to become a pointer to 6200Sstevel@tonic-gate * the other. We do this so we have a means later for tracking 6210Sstevel@tonic-gate * who is referencing us when we get back the real pointer 6220Sstevel@tonic-gate * in is_rule after doing the ioctl. 6230Sstevel@tonic-gate */ 6240Sstevel@tonic-gate nat = &in->ipn_nat; 6250Sstevel@tonic-gate if (nat->nat_fr != NULL) { 6260Sstevel@tonic-gate for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next) 6270Sstevel@tonic-gate if (in1->ipn_rule == nat->nat_fr) 6280Sstevel@tonic-gate break; 6290Sstevel@tonic-gate if (in1 == NULL) 6300Sstevel@tonic-gate nat->nat_flags |= SI_NEWFR; 6310Sstevel@tonic-gate else 6320Sstevel@tonic-gate nat->nat_fr = &in1->ipn_fr; 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate /* 6360Sstevel@tonic-gate * Use a tail-queue type list (add things to the end).. 6370Sstevel@tonic-gate */ 6380Sstevel@tonic-gate in->ipn_next = NULL; 6390Sstevel@tonic-gate if (!ipnhead) 6400Sstevel@tonic-gate ipnhead = in; 6410Sstevel@tonic-gate if (ipntail) 6420Sstevel@tonic-gate ipntail->ipn_next = in; 6430Sstevel@tonic-gate ipntail = in; 6440Sstevel@tonic-gate } while (1); 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate close(nfd); 647*2393Syz155240 nfd = -1; 648*2393Syz155240 649*2393Syz155240 obj.ipfo_rev = IPFILTER_VERSION; 650*2393Syz155240 obj.ipfo_type = IPFOBJ_NATSAVE; 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate for (in = ipnhead; in; in = in->ipn_next) { 6530Sstevel@tonic-gate if (opts & OPT_VERBOSE) 6540Sstevel@tonic-gate printf("Loading new NAT table entry\n"); 6550Sstevel@tonic-gate nat = &in->ipn_nat; 6560Sstevel@tonic-gate if (nat->nat_flags & SI_NEWFR) { 6570Sstevel@tonic-gate if (opts & OPT_VERBOSE) 6580Sstevel@tonic-gate printf("Loading new filter rule\n"); 6590Sstevel@tonic-gate } 660*2393Syz155240 661*2393Syz155240 obj.ipfo_ptr = in; 662*2393Syz155240 obj.ipfo_size = in->ipn_dsize; 6630Sstevel@tonic-gate if (!(opts & OPT_DONOTHING)) 664*2393Syz155240 if (ioctl(fd, SIOCSTPUT, &obj)) { 665*2393Syz155240 fprintf(stderr, "in=%p:", in); 6660Sstevel@tonic-gate perror("SIOCSTPUT"); 6670Sstevel@tonic-gate return 1; 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate if (nat->nat_flags & SI_NEWFR) { 6710Sstevel@tonic-gate if (opts & OPT_VERBOSE) 6720Sstevel@tonic-gate printf("Real rule addr %p\n", nat->nat_fr); 6730Sstevel@tonic-gate for (in1 = in->ipn_next; in1; in1 = in1->ipn_next) 6740Sstevel@tonic-gate if (in1->ipn_rule == &in->ipn_fr) 6750Sstevel@tonic-gate in1->ipn_rule = nat->nat_fr; 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate return 0; 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate int writenat(fd, file) 6840Sstevel@tonic-gate int fd; 6850Sstevel@tonic-gate char *file; 6860Sstevel@tonic-gate { 6870Sstevel@tonic-gate nat_save_t *ipnp = NULL, *next = NULL; 688*2393Syz155240 ipfobj_t obj; 6890Sstevel@tonic-gate int nfd = -1; 6900Sstevel@tonic-gate natget_t ng; 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate if (!file) 6930Sstevel@tonic-gate file = IPF_NATFILE; 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); 6960Sstevel@tonic-gate if (nfd == -1) { 6970Sstevel@tonic-gate fprintf(stderr, "%s ", file); 6980Sstevel@tonic-gate perror("nat:open"); 6990Sstevel@tonic-gate return 1; 7000Sstevel@tonic-gate } 7010Sstevel@tonic-gate 702*2393Syz155240 obj.ipfo_rev = IPFILTER_VERSION; 703*2393Syz155240 obj.ipfo_type = IPFOBJ_NATSAVE; 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate do { 7060Sstevel@tonic-gate if (opts & OPT_VERBOSE) 7070Sstevel@tonic-gate printf("Getting nat from addr %p\n", ipnp); 7080Sstevel@tonic-gate ng.ng_ptr = next; 7090Sstevel@tonic-gate ng.ng_sz = 0; 7100Sstevel@tonic-gate if (ioctl(fd, SIOCSTGSZ, &ng)) { 7110Sstevel@tonic-gate perror("nat:SIOCSTGSZ"); 7120Sstevel@tonic-gate close(nfd); 7130Sstevel@tonic-gate if (ipnp != NULL) 7140Sstevel@tonic-gate free(ipnp); 7150Sstevel@tonic-gate return 1; 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate if (opts & OPT_VERBOSE) 7190Sstevel@tonic-gate printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr); 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate if (ng.ng_sz == 0) 7220Sstevel@tonic-gate break; 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate if (!ipnp) 7250Sstevel@tonic-gate ipnp = malloc(ng.ng_sz); 7260Sstevel@tonic-gate else 7270Sstevel@tonic-gate ipnp = realloc((char *)ipnp, ng.ng_sz); 7280Sstevel@tonic-gate if (!ipnp) { 7290Sstevel@tonic-gate fprintf(stderr, 7300Sstevel@tonic-gate "malloc for %d bytes failed\n", ng.ng_sz); 7310Sstevel@tonic-gate break; 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate bzero((char *)ipnp, ng.ng_sz); 735*2393Syz155240 obj.ipfo_size = ng.ng_sz; 736*2393Syz155240 obj.ipfo_ptr = ipnp; 737*2393Syz155240 ipnp->ipn_dsize = ng.ng_sz; 7380Sstevel@tonic-gate ipnp->ipn_next = next; 739*2393Syz155240 if (ioctl(fd, SIOCSTGET, &obj)) { 7400Sstevel@tonic-gate if (errno == ENOENT) 7410Sstevel@tonic-gate break; 7420Sstevel@tonic-gate perror("nat:SIOCSTGET"); 7430Sstevel@tonic-gate close(nfd); 7440Sstevel@tonic-gate free(ipnp); 7450Sstevel@tonic-gate return 1; 7460Sstevel@tonic-gate } 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate if (opts & OPT_VERBOSE) 749*2393Syz155240 printf("Got nat next %p ipn_dsize %d ng_sz %d\n", 750*2393Syz155240 ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz); 751*2393Syz155240 if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) { 7520Sstevel@tonic-gate perror("nat:write"); 7530Sstevel@tonic-gate close(nfd); 7540Sstevel@tonic-gate free(ipnp); 7550Sstevel@tonic-gate return 1; 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate next = ipnp->ipn_next; 7580Sstevel@tonic-gate } while (ipnp && next); 7590Sstevel@tonic-gate if (ipnp != NULL) 7600Sstevel@tonic-gate free(ipnp); 7610Sstevel@tonic-gate close(nfd); 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate return 0; 7640Sstevel@tonic-gate } 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate int writeall(dirname) 7680Sstevel@tonic-gate char *dirname; 7690Sstevel@tonic-gate { 7700Sstevel@tonic-gate int fd, devfd; 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate if (!dirname) 7730Sstevel@tonic-gate dirname = IPF_SAVEDIR; 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate if (chdir(dirname)) { 776*2393Syz155240 fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname); 7770Sstevel@tonic-gate perror("chdir(IPF_SAVEDIR)"); 7780Sstevel@tonic-gate return 1; 7790Sstevel@tonic-gate } 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate fd = opendevice(NULL); 7820Sstevel@tonic-gate if (fd == -1) 7830Sstevel@tonic-gate return 1; 7840Sstevel@tonic-gate if (setlock(fd, 1)) { 7850Sstevel@tonic-gate close(fd); 7860Sstevel@tonic-gate return 1; 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate devfd = opendevice(IPSTATE_NAME); 7900Sstevel@tonic-gate if (devfd == -1) 7910Sstevel@tonic-gate goto bad; 7920Sstevel@tonic-gate if (writestate(devfd, NULL)) 7930Sstevel@tonic-gate goto bad; 7940Sstevel@tonic-gate close(devfd); 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate devfd = opendevice(IPNAT_NAME); 7970Sstevel@tonic-gate if (devfd == -1) 7980Sstevel@tonic-gate goto bad; 7990Sstevel@tonic-gate if (writenat(devfd, NULL)) 8000Sstevel@tonic-gate goto bad; 8010Sstevel@tonic-gate close(devfd); 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate if (setlock(fd, 0)) { 8040Sstevel@tonic-gate close(fd); 8050Sstevel@tonic-gate return 1; 8060Sstevel@tonic-gate } 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate close(fd); 8090Sstevel@tonic-gate return 0; 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate bad: 8120Sstevel@tonic-gate setlock(fd, 0); 8130Sstevel@tonic-gate close(fd); 8140Sstevel@tonic-gate return 1; 8150Sstevel@tonic-gate } 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate 8180Sstevel@tonic-gate int readall(dirname) 8190Sstevel@tonic-gate char *dirname; 8200Sstevel@tonic-gate { 8210Sstevel@tonic-gate int fd, devfd; 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate if (!dirname) 8240Sstevel@tonic-gate dirname = IPF_SAVEDIR; 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate if (chdir(dirname)) { 8270Sstevel@tonic-gate perror("chdir(IPF_SAVEDIR)"); 8280Sstevel@tonic-gate return 1; 8290Sstevel@tonic-gate } 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate fd = opendevice(NULL); 8320Sstevel@tonic-gate if (fd == -1) 8330Sstevel@tonic-gate return 1; 8340Sstevel@tonic-gate if (setlock(fd, 1)) { 8350Sstevel@tonic-gate close(fd); 8360Sstevel@tonic-gate return 1; 8370Sstevel@tonic-gate } 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate devfd = opendevice(IPSTATE_NAME); 8400Sstevel@tonic-gate if (devfd == -1) 8410Sstevel@tonic-gate return 1; 8420Sstevel@tonic-gate if (readstate(devfd, NULL)) 8430Sstevel@tonic-gate return 1; 8440Sstevel@tonic-gate close(devfd); 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate devfd = opendevice(IPNAT_NAME); 8470Sstevel@tonic-gate if (devfd == -1) 8480Sstevel@tonic-gate return 1; 8490Sstevel@tonic-gate if (readnat(devfd, NULL)) 8500Sstevel@tonic-gate return 1; 8510Sstevel@tonic-gate close(devfd); 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate if (setlock(fd, 0)) { 8540Sstevel@tonic-gate close(fd); 8550Sstevel@tonic-gate return 1; 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate return 0; 8590Sstevel@tonic-gate } 860