ipfs.c revision 161357
1145519Sdarrenr/* $FreeBSD: head/contrib/ipfilter/tools/ipfs.c 161357 2006-08-16 12:23:02Z guido $ */ 2145510Sdarrenr 3145510Sdarrenr/* 4145510Sdarrenr * Copyright (C) 1999-2001, 2003 by Darren Reed. 5145510Sdarrenr * 6145510Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 7145510Sdarrenr */ 8145510Sdarrenr#ifdef __FreeBSD__ 9145510Sdarrenr# ifndef __FreeBSD_cc_version 10145510Sdarrenr# include <osreldate.h> 11145510Sdarrenr# else 12145510Sdarrenr# if __FreeBSD_cc_version < 430000 13145510Sdarrenr# include <osreldate.h> 14145510Sdarrenr# endif 15145510Sdarrenr# endif 16145510Sdarrenr#endif 17145510Sdarrenr#include <stdio.h> 18145510Sdarrenr#include <unistd.h> 19145510Sdarrenr#include <string.h> 20145510Sdarrenr#include <fcntl.h> 21145510Sdarrenr#include <errno.h> 22145510Sdarrenr#if !defined(__SVR4) && !defined(__GNUC__) 23145510Sdarrenr#include <strings.h> 24145510Sdarrenr#endif 25145510Sdarrenr#include <sys/types.h> 26145510Sdarrenr#include <sys/param.h> 27145510Sdarrenr#include <sys/file.h> 28145510Sdarrenr#include <stdlib.h> 29145510Sdarrenr#include <stddef.h> 30145510Sdarrenr#include <sys/socket.h> 31145510Sdarrenr#include <sys/ioctl.h> 32145510Sdarrenr#include <netinet/in.h> 33145510Sdarrenr#include <netinet/in_systm.h> 34145510Sdarrenr#include <sys/time.h> 35145510Sdarrenr#include <net/if.h> 36145510Sdarrenr#if __FreeBSD_version >= 300000 37145510Sdarrenr# include <net/if_var.h> 38145510Sdarrenr#endif 39145510Sdarrenr#include <netinet/ip.h> 40145510Sdarrenr#include <netdb.h> 41145510Sdarrenr#include <arpa/nameser.h> 42145510Sdarrenr#include <resolv.h> 43145510Sdarrenr#include "ipf.h" 44145554Sdarrenr#include "netinet/ipl.h" 45145510Sdarrenr 46145510Sdarrenr#if !defined(lint) 47145510Sdarrenrstatic const char rcsid[] = "@(#)Id: ipfs.c,v 1.12 2003/12/01 01:56:53 darrenr Exp"; 48145510Sdarrenr#endif 49145510Sdarrenr 50145510Sdarrenr#ifndef IPF_SAVEDIR 51145510Sdarrenr# define IPF_SAVEDIR "/var/db/ipf" 52145510Sdarrenr#endif 53145510Sdarrenr#ifndef IPF_NATFILE 54145510Sdarrenr# define IPF_NATFILE "ipnat.ipf" 55145510Sdarrenr#endif 56145510Sdarrenr#ifndef IPF_STATEFILE 57145510Sdarrenr# define IPF_STATEFILE "ipstate.ipf" 58145510Sdarrenr#endif 59145510Sdarrenr 60145510Sdarrenr#if !defined(__SVR4) && defined(__GNUC__) 61145510Sdarrenrextern char *index __P((const char *, int)); 62145510Sdarrenr#endif 63145510Sdarrenr 64145510Sdarrenrextern char *optarg; 65145510Sdarrenrextern int optind; 66145510Sdarrenr 67145510Sdarrenrint main __P((int, char *[])); 68145510Sdarrenrvoid usage __P((void)); 69145510Sdarrenrint changestateif __P((char *, char *)); 70145510Sdarrenrint changenatif __P((char *, char *)); 71145510Sdarrenrint readstate __P((int, char *)); 72145510Sdarrenrint readnat __P((int, char *)); 73145510Sdarrenrint writestate __P((int, char *)); 74145510Sdarrenrint opendevice __P((char *)); 75145510Sdarrenrvoid closedevice __P((int)); 76145510Sdarrenrint setlock __P((int, int)); 77145510Sdarrenrint writeall __P((char *)); 78145510Sdarrenrint readall __P((char *)); 79145510Sdarrenrint writenat __P((int, char *)); 80145510Sdarrenr 81145510Sdarrenrint opts = 0; 82145510Sdarrenrchar *progname; 83145510Sdarrenr 84145510Sdarrenr 85145510Sdarrenrvoid usage() 86145510Sdarrenr{ 87145510Sdarrenr fprintf(stderr, "usage: %s [-nv] -l\n", progname); 88145510Sdarrenr fprintf(stderr, "usage: %s [-nv] -u\n", progname); 89145510Sdarrenr fprintf(stderr, "usage: %s [-nv] [-d <dir>] -R\n", progname); 90145510Sdarrenr fprintf(stderr, "usage: %s [-nv] [-d <dir>] -W\n", progname); 91145510Sdarrenr fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -r\n", progname); 92145510Sdarrenr fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -w\n", progname); 93145510Sdarrenr fprintf(stderr, "usage: %s [-nNSv] -f <filename> -i <if1>,<if2>\n", 94145510Sdarrenr progname); 95145510Sdarrenr exit(1); 96145510Sdarrenr} 97145510Sdarrenr 98145510Sdarrenr 99145510Sdarrenr/* 100145510Sdarrenr * Change interface names in state information saved out to disk. 101145510Sdarrenr */ 102145510Sdarrenrint changestateif(ifs, fname) 103145510Sdarrenrchar *ifs, *fname; 104145510Sdarrenr{ 105145510Sdarrenr int fd, olen, nlen, rw; 106145510Sdarrenr ipstate_save_t ips; 107145510Sdarrenr off_t pos; 108145510Sdarrenr char *s; 109145510Sdarrenr 110145510Sdarrenr s = strchr(ifs, ','); 111145510Sdarrenr if (!s) 112145510Sdarrenr usage(); 113145510Sdarrenr *s++ = '\0'; 114145510Sdarrenr nlen = strlen(s); 115145510Sdarrenr olen = strlen(ifs); 116145510Sdarrenr if (nlen >= sizeof(ips.ips_is.is_ifname) || 117145510Sdarrenr olen >= sizeof(ips.ips_is.is_ifname)) 118145510Sdarrenr usage(); 119145510Sdarrenr 120145510Sdarrenr fd = open(fname, O_RDWR); 121145510Sdarrenr if (fd == -1) { 122145510Sdarrenr perror("open"); 123145510Sdarrenr exit(1); 124145510Sdarrenr } 125145510Sdarrenr 126145510Sdarrenr for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) { 127145510Sdarrenr rw = 0; 128145510Sdarrenr if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) { 129145510Sdarrenr strcpy(ips.ips_is.is_ifname[0], s); 130145510Sdarrenr rw = 1; 131145510Sdarrenr } 132145510Sdarrenr if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) { 133145510Sdarrenr strcpy(ips.ips_is.is_ifname[1], s); 134145510Sdarrenr rw = 1; 135145510Sdarrenr } 136145510Sdarrenr if (rw == 1) { 137145510Sdarrenr if (lseek(fd, pos, SEEK_SET) != pos) { 138145510Sdarrenr perror("lseek"); 139145510Sdarrenr exit(1); 140145510Sdarrenr } 141145510Sdarrenr if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) { 142145510Sdarrenr perror("write"); 143145510Sdarrenr exit(1); 144145510Sdarrenr } 145145510Sdarrenr } 146145510Sdarrenr pos = lseek(fd, 0, SEEK_CUR); 147145510Sdarrenr } 148145510Sdarrenr close(fd); 149145510Sdarrenr 150145510Sdarrenr return 0; 151145510Sdarrenr} 152145510Sdarrenr 153145510Sdarrenr 154145510Sdarrenr/* 155145510Sdarrenr * Change interface names in NAT information saved out to disk. 156145510Sdarrenr */ 157145510Sdarrenrint changenatif(ifs, fname) 158145510Sdarrenrchar *ifs, *fname; 159145510Sdarrenr{ 160145510Sdarrenr int fd, olen, nlen, rw; 161145510Sdarrenr nat_save_t ipn; 162145510Sdarrenr nat_t *nat; 163145510Sdarrenr off_t pos; 164145510Sdarrenr char *s; 165145510Sdarrenr 166145510Sdarrenr s = strchr(ifs, ','); 167145510Sdarrenr if (!s) 168145510Sdarrenr usage(); 169145510Sdarrenr *s++ = '\0'; 170145510Sdarrenr nlen = strlen(s); 171145510Sdarrenr olen = strlen(ifs); 172145510Sdarrenr nat = &ipn.ipn_nat; 173145510Sdarrenr if (nlen >= sizeof(nat->nat_ifnames[0]) || 174145510Sdarrenr olen >= sizeof(nat->nat_ifnames[0])) 175145510Sdarrenr usage(); 176145510Sdarrenr 177145510Sdarrenr fd = open(fname, O_RDWR); 178145510Sdarrenr if (fd == -1) { 179145510Sdarrenr perror("open"); 180145510Sdarrenr exit(1); 181145510Sdarrenr } 182145510Sdarrenr 183145510Sdarrenr for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) { 184145510Sdarrenr rw = 0; 185145510Sdarrenr if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) { 186145510Sdarrenr strcpy(nat->nat_ifnames[0], s); 187145510Sdarrenr rw = 1; 188145510Sdarrenr } 189145510Sdarrenr if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) { 190145510Sdarrenr strcpy(nat->nat_ifnames[1], s); 191145510Sdarrenr rw = 1; 192145510Sdarrenr } 193145510Sdarrenr if (rw == 1) { 194145510Sdarrenr if (lseek(fd, pos, SEEK_SET) != pos) { 195145510Sdarrenr perror("lseek"); 196145510Sdarrenr exit(1); 197145510Sdarrenr } 198145510Sdarrenr if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) { 199145510Sdarrenr perror("write"); 200145510Sdarrenr exit(1); 201145510Sdarrenr } 202145510Sdarrenr } 203145510Sdarrenr pos = lseek(fd, 0, SEEK_CUR); 204145510Sdarrenr } 205145510Sdarrenr close(fd); 206145510Sdarrenr 207145510Sdarrenr return 0; 208145510Sdarrenr} 209145510Sdarrenr 210145510Sdarrenr 211145510Sdarrenrint main(argc,argv) 212145510Sdarrenrint argc; 213145510Sdarrenrchar *argv[]; 214145510Sdarrenr{ 215145510Sdarrenr int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0; 216145510Sdarrenr char *dirname = NULL, *filename = NULL, *ifs = NULL; 217145510Sdarrenr 218145510Sdarrenr progname = argv[0]; 219145510Sdarrenr while ((c = getopt(argc, argv, "d:f:lNnSRruvWw")) != -1) 220145510Sdarrenr switch (c) 221145510Sdarrenr { 222145510Sdarrenr case 'd' : 223145510Sdarrenr if ((set == 0) && !dirname && !filename) 224145510Sdarrenr dirname = optarg; 225145510Sdarrenr else 226145510Sdarrenr usage(); 227145510Sdarrenr break; 228145510Sdarrenr case 'f' : 229145510Sdarrenr if ((set != 0) && !dirname && !filename) 230145510Sdarrenr filename = optarg; 231145510Sdarrenr else 232145510Sdarrenr usage(); 233145510Sdarrenr break; 234145510Sdarrenr case 'i' : 235145510Sdarrenr ifs = optarg; 236145510Sdarrenr set = 1; 237145510Sdarrenr break; 238145510Sdarrenr case 'l' : 239145510Sdarrenr if (filename || dirname || set) 240145510Sdarrenr usage(); 241145510Sdarrenr lock = 1; 242145510Sdarrenr set = 1; 243145510Sdarrenr break; 244145510Sdarrenr case 'n' : 245145510Sdarrenr opts |= OPT_DONOTHING; 246145510Sdarrenr break; 247145510Sdarrenr case 'N' : 248145510Sdarrenr if ((ns >= 0) || dirname || (rw != -1) || set) 249145510Sdarrenr usage(); 250145510Sdarrenr ns = 0; 251145510Sdarrenr set = 1; 252145510Sdarrenr break; 253145510Sdarrenr case 'r' : 254145510Sdarrenr if (dirname || (rw != -1) || (ns == -1)) 255145510Sdarrenr usage(); 256145510Sdarrenr rw = 0; 257145510Sdarrenr set = 1; 258145510Sdarrenr break; 259145510Sdarrenr case 'R' : 260145510Sdarrenr rw = 2; 261145510Sdarrenr set = 1; 262145510Sdarrenr break; 263145510Sdarrenr case 'S' : 264145510Sdarrenr if ((ns >= 0) || dirname || (rw != -1) || set) 265145510Sdarrenr usage(); 266145510Sdarrenr ns = 1; 267145510Sdarrenr set = 1; 268145510Sdarrenr break; 269145510Sdarrenr case 'u' : 270145510Sdarrenr if (filename || dirname || set) 271145510Sdarrenr usage(); 272145510Sdarrenr lock = 0; 273145510Sdarrenr set = 1; 274145510Sdarrenr break; 275145510Sdarrenr case 'v' : 276145510Sdarrenr opts |= OPT_VERBOSE; 277145510Sdarrenr break; 278145510Sdarrenr case 'w' : 279145510Sdarrenr if (dirname || (rw != -1) || (ns == -1)) 280145510Sdarrenr usage(); 281145510Sdarrenr rw = 1; 282145510Sdarrenr set = 1; 283145510Sdarrenr break; 284145510Sdarrenr case 'W' : 285145510Sdarrenr rw = 3; 286145510Sdarrenr set = 1; 287145510Sdarrenr break; 288145510Sdarrenr case '?' : 289145510Sdarrenr default : 290145510Sdarrenr usage(); 291145510Sdarrenr } 292145510Sdarrenr 293145510Sdarrenr if (ifs) { 294145510Sdarrenr if (!filename || ns < 0) 295145510Sdarrenr usage(); 296145510Sdarrenr if (ns == 0) 297145510Sdarrenr return changenatif(ifs, filename); 298145510Sdarrenr else 299145510Sdarrenr return changestateif(ifs, filename); 300145510Sdarrenr } 301145510Sdarrenr 302145510Sdarrenr if ((ns >= 0) || (lock >= 0)) { 303145510Sdarrenr if (lock >= 0) 304145510Sdarrenr devfd = opendevice(NULL); 305145510Sdarrenr else if (ns >= 0) { 306145510Sdarrenr if (ns == 1) 307145510Sdarrenr devfd = opendevice(IPSTATE_NAME); 308145510Sdarrenr else if (ns == 0) 309145510Sdarrenr devfd = opendevice(IPNAT_NAME); 310145510Sdarrenr } 311145510Sdarrenr if (devfd == -1) 312145510Sdarrenr exit(1); 313145510Sdarrenr } 314145510Sdarrenr 315145510Sdarrenr if (lock >= 0) 316145510Sdarrenr err = setlock(devfd, lock); 317145510Sdarrenr else if (rw >= 0) { 318145510Sdarrenr if (rw & 1) { /* WRITE */ 319145510Sdarrenr if (rw & 2) 320145510Sdarrenr err = writeall(dirname); 321145510Sdarrenr else { 322145510Sdarrenr if (ns == 0) 323145510Sdarrenr err = writenat(devfd, filename); 324145510Sdarrenr else if (ns == 1) 325145510Sdarrenr err = writestate(devfd, filename); 326145510Sdarrenr } 327145510Sdarrenr } else { 328145510Sdarrenr if (rw & 2) 329145510Sdarrenr err = readall(dirname); 330145510Sdarrenr else { 331145510Sdarrenr if (ns == 0) 332145510Sdarrenr err = readnat(devfd, filename); 333145510Sdarrenr else if (ns == 1) 334145510Sdarrenr err = readstate(devfd, filename); 335145510Sdarrenr } 336145510Sdarrenr } 337145510Sdarrenr } 338145510Sdarrenr return err; 339145510Sdarrenr} 340145510Sdarrenr 341145510Sdarrenr 342145510Sdarrenrint opendevice(ipfdev) 343145510Sdarrenrchar *ipfdev; 344145510Sdarrenr{ 345145510Sdarrenr int fd = -1; 346145510Sdarrenr 347145510Sdarrenr if (opts & OPT_DONOTHING) 348145510Sdarrenr return -2; 349145510Sdarrenr 350145510Sdarrenr if (!ipfdev) 351145510Sdarrenr ipfdev = IPL_NAME; 352145510Sdarrenr 353145510Sdarrenr if ((fd = open(ipfdev, O_RDWR)) == -1) 354145510Sdarrenr if ((fd = open(ipfdev, O_RDONLY)) == -1) 355145510Sdarrenr perror("open device"); 356145510Sdarrenr return fd; 357145510Sdarrenr} 358145510Sdarrenr 359145510Sdarrenr 360145510Sdarrenrvoid closedevice(fd) 361145510Sdarrenrint fd; 362145510Sdarrenr{ 363145510Sdarrenr close(fd); 364145510Sdarrenr} 365145510Sdarrenr 366145510Sdarrenr 367145510Sdarrenrint setlock(fd, lock) 368145510Sdarrenrint fd, lock; 369145510Sdarrenr{ 370145510Sdarrenr if (opts & OPT_VERBOSE) 371145510Sdarrenr printf("Turn lock %s\n", lock ? "on" : "off"); 372145510Sdarrenr if (!(opts & OPT_DONOTHING)) { 373145510Sdarrenr if (ioctl(fd, SIOCSTLCK, &lock) == -1) { 374145510Sdarrenr perror("SIOCSTLCK"); 375145510Sdarrenr return 1; 376145510Sdarrenr } 377145510Sdarrenr if (opts & OPT_VERBOSE) 378145510Sdarrenr printf("Lock now %s\n", lock ? "on" : "off"); 379145510Sdarrenr } 380145510Sdarrenr return 0; 381145510Sdarrenr} 382145510Sdarrenr 383145510Sdarrenr 384145510Sdarrenrint writestate(fd, file) 385145510Sdarrenrint fd; 386145510Sdarrenrchar *file; 387145510Sdarrenr{ 388145510Sdarrenr ipstate_save_t ips, *ipsp; 389145510Sdarrenr ipfobj_t obj; 390145510Sdarrenr int wfd = -1; 391145510Sdarrenr 392145510Sdarrenr if (!file) 393145510Sdarrenr file = IPF_STATEFILE; 394145510Sdarrenr 395145510Sdarrenr wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); 396145510Sdarrenr if (wfd == -1) { 397145510Sdarrenr fprintf(stderr, "%s ", file); 398145510Sdarrenr perror("state:open"); 399145510Sdarrenr return 1; 400145510Sdarrenr } 401145510Sdarrenr 402145510Sdarrenr ipsp = &ips; 403145510Sdarrenr bzero((char *)&obj, sizeof(obj)); 404145510Sdarrenr bzero((char *)ipsp, sizeof(ips)); 405145510Sdarrenr 406145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 407145510Sdarrenr obj.ipfo_size = sizeof(*ipsp); 408145510Sdarrenr obj.ipfo_type = IPFOBJ_STATESAVE; 409145510Sdarrenr obj.ipfo_ptr = ipsp; 410145510Sdarrenr 411145510Sdarrenr do { 412145510Sdarrenr 413145510Sdarrenr if (opts & OPT_VERBOSE) 414145510Sdarrenr printf("Getting state from addr %p\n", ips.ips_next); 415145510Sdarrenr if (ioctl(fd, SIOCSTGET, &obj)) { 416145510Sdarrenr if (errno == ENOENT) 417145510Sdarrenr break; 418145510Sdarrenr perror("state:SIOCSTGET"); 419145510Sdarrenr close(wfd); 420145510Sdarrenr return 1; 421145510Sdarrenr } 422145510Sdarrenr if (opts & OPT_VERBOSE) 423145510Sdarrenr printf("Got state next %p\n", ips.ips_next); 424145510Sdarrenr if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) { 425145510Sdarrenr perror("state:write"); 426145510Sdarrenr close(wfd); 427145510Sdarrenr return 1; 428145510Sdarrenr } 429145510Sdarrenr } while (ips.ips_next != NULL); 430145510Sdarrenr close(wfd); 431145510Sdarrenr 432145510Sdarrenr return 0; 433145510Sdarrenr} 434145510Sdarrenr 435145510Sdarrenr 436145510Sdarrenrint readstate(fd, file) 437145510Sdarrenrint fd; 438145510Sdarrenrchar *file; 439145510Sdarrenr{ 440145510Sdarrenr ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL; 441145510Sdarrenr int sfd = -1, i; 442145510Sdarrenr ipfobj_t obj; 443145510Sdarrenr 444145510Sdarrenr if (!file) 445145510Sdarrenr file = IPF_STATEFILE; 446145510Sdarrenr 447145510Sdarrenr sfd = open(file, O_RDONLY, 0600); 448145510Sdarrenr if (sfd == -1) { 449145510Sdarrenr fprintf(stderr, "%s ", file); 450145510Sdarrenr perror("open"); 451145510Sdarrenr return 1; 452145510Sdarrenr } 453145510Sdarrenr 454145510Sdarrenr bzero((char *)&ips, sizeof(ips)); 455145510Sdarrenr 456145510Sdarrenr /* 457145510Sdarrenr * 1. Read all state information in. 458145510Sdarrenr */ 459145510Sdarrenr do { 460145510Sdarrenr i = read(sfd, &ips, sizeof(ips)); 461145510Sdarrenr if (i == -1) { 462145510Sdarrenr perror("read"); 463161357Sguido goto freeipshead; 464145510Sdarrenr } 465145510Sdarrenr if (i == 0) 466145510Sdarrenr break; 467145510Sdarrenr if (i != sizeof(ips)) { 468145510Sdarrenr fprintf(stderr, "state:incomplete read: %d != %d\n", 469145510Sdarrenr i, (int)sizeof(ips)); 470161357Sguido goto freeipshead; 471145510Sdarrenr } 472145510Sdarrenr is = (ipstate_save_t *)malloc(sizeof(*is)); 473161357Sguido if (is == NULL) { 474145510Sdarrenr fprintf(stderr, "malloc failed\n"); 475161357Sguido goto freeipshead; 476145510Sdarrenr } 477145510Sdarrenr 478145510Sdarrenr bcopy((char *)&ips, (char *)is, sizeof(ips)); 479145510Sdarrenr 480145510Sdarrenr /* 481145510Sdarrenr * Check to see if this is the first state entry that will 482145510Sdarrenr * reference a particular rule and if so, flag it as such 483145510Sdarrenr * else just adjust the rule pointer to become a pointer to 484145510Sdarrenr * the other. We do this so we have a means later for tracking 485145510Sdarrenr * who is referencing us when we get back the real pointer 486145510Sdarrenr * in is_rule after doing the ioctl. 487145510Sdarrenr */ 488145510Sdarrenr for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next) 489145510Sdarrenr if (is1->ips_rule == is->ips_rule) 490145510Sdarrenr break; 491145510Sdarrenr if (is1 == NULL) 492145510Sdarrenr is->ips_is.is_flags |= SI_NEWFR; 493145510Sdarrenr else 494145510Sdarrenr is->ips_rule = (void *)&is1->ips_rule; 495145510Sdarrenr 496145510Sdarrenr /* 497145510Sdarrenr * Use a tail-queue type list (add things to the end).. 498145510Sdarrenr */ 499145510Sdarrenr is->ips_next = NULL; 500145510Sdarrenr if (!ipshead) 501145510Sdarrenr ipshead = is; 502145510Sdarrenr if (ipstail) 503145510Sdarrenr ipstail->ips_next = is; 504145510Sdarrenr ipstail = is; 505145510Sdarrenr } while (1); 506145510Sdarrenr 507145510Sdarrenr close(sfd); 508145510Sdarrenr 509145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 510145510Sdarrenr obj.ipfo_size = sizeof(*is); 511145510Sdarrenr obj.ipfo_type = IPFOBJ_STATESAVE; 512145510Sdarrenr 513161357Sguido while ((is = ipshead) != NULL) { 514145510Sdarrenr if (opts & OPT_VERBOSE) 515145510Sdarrenr printf("Loading new state table entry\n"); 516145510Sdarrenr if (is->ips_is.is_flags & SI_NEWFR) { 517145510Sdarrenr if (opts & OPT_VERBOSE) 518145510Sdarrenr printf("Loading new filter rule\n"); 519145510Sdarrenr } 520145510Sdarrenr 521145510Sdarrenr obj.ipfo_ptr = is; 522145510Sdarrenr if (!(opts & OPT_DONOTHING)) 523145510Sdarrenr if (ioctl(fd, SIOCSTPUT, &obj)) { 524145510Sdarrenr perror("SIOCSTPUT"); 525161357Sguido goto freeipshead; 526145510Sdarrenr } 527145510Sdarrenr 528145510Sdarrenr if (is->ips_is.is_flags & SI_NEWFR) { 529145510Sdarrenr if (opts & OPT_VERBOSE) 530145510Sdarrenr printf("Real rule addr %p\n", is->ips_rule); 531145510Sdarrenr for (is1 = is->ips_next; is1; is1 = is1->ips_next) 532145510Sdarrenr if (is1->ips_rule == (frentry_t *)&is->ips_rule) 533145510Sdarrenr is1->ips_rule = is->ips_rule; 534145510Sdarrenr } 535161357Sguido 536161357Sguido ipshead = is->ips_next; 537161357Sguido free(is); 538145510Sdarrenr } 539145510Sdarrenr 540145510Sdarrenr return 0; 541161357Sguido 542161357Sguidofreeipshead: 543161357Sguido while ((is = ipshead) != NULL) { 544161357Sguido ipshead = is->ips_next; 545161357Sguido free(is); 546161357Sguido } 547161357Sguido if (sfd != -1) 548161357Sguido close(sfd); 549161357Sguido return 1; 550145510Sdarrenr} 551145510Sdarrenr 552145510Sdarrenr 553145510Sdarrenrint readnat(fd, file) 554145510Sdarrenrint fd; 555145510Sdarrenrchar *file; 556145510Sdarrenr{ 557145510Sdarrenr nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL; 558145510Sdarrenr ipfobj_t obj; 559145510Sdarrenr int nfd, i; 560145510Sdarrenr nat_t *nat; 561145510Sdarrenr char *s; 562145510Sdarrenr int n; 563145510Sdarrenr 564145510Sdarrenr nfd = -1; 565145510Sdarrenr in = NULL; 566145510Sdarrenr ipnhead = NULL; 567145510Sdarrenr ipntail = NULL; 568145510Sdarrenr 569145510Sdarrenr if (!file) 570145510Sdarrenr file = IPF_NATFILE; 571145510Sdarrenr 572145510Sdarrenr nfd = open(file, O_RDONLY); 573145510Sdarrenr if (nfd == -1) { 574145510Sdarrenr fprintf(stderr, "%s ", file); 575145510Sdarrenr perror("nat:open"); 576145510Sdarrenr return 1; 577145510Sdarrenr } 578145510Sdarrenr 579145510Sdarrenr bzero((char *)&ipn, sizeof(ipn)); 580145510Sdarrenr 581145510Sdarrenr /* 582145510Sdarrenr * 1. Read all state information in. 583145510Sdarrenr */ 584145510Sdarrenr do { 585145510Sdarrenr i = read(nfd, &ipn, sizeof(ipn)); 586145510Sdarrenr if (i == -1) { 587145510Sdarrenr perror("read"); 588161357Sguido goto freenathead; 589145510Sdarrenr } 590145510Sdarrenr if (i == 0) 591145510Sdarrenr break; 592145510Sdarrenr if (i != sizeof(ipn)) { 593145510Sdarrenr fprintf(stderr, "nat:incomplete read: %d != %d\n", 594145510Sdarrenr i, (int)sizeof(ipn)); 595161357Sguido goto freenathead; 596145510Sdarrenr } 597145510Sdarrenr 598145510Sdarrenr in = (nat_save_t *)malloc(ipn.ipn_dsize); 599161357Sguido if (in == NULL) { 600161357Sguido fprintf(stderr, "nat:cannot malloc nat save atruct\n"); 601161357Sguido goto freenathead; 602161357Sguido } 603145510Sdarrenr 604145510Sdarrenr if (ipn.ipn_dsize > sizeof(ipn)) { 605145510Sdarrenr n = ipn.ipn_dsize - sizeof(ipn); 606145510Sdarrenr if (n > 0) { 607145510Sdarrenr s = in->ipn_data + sizeof(in->ipn_data); 608145510Sdarrenr i = read(nfd, s, n); 609145510Sdarrenr if (i == 0) 610145510Sdarrenr break; 611145510Sdarrenr if (i != n) { 612145510Sdarrenr fprintf(stderr, 613145510Sdarrenr "nat:incomplete read: %d != %d\n", 614145510Sdarrenr i, n); 615161357Sguido goto freenathead; 616145510Sdarrenr } 617145510Sdarrenr } 618145510Sdarrenr } 619145510Sdarrenr bcopy((char *)&ipn, (char *)in, sizeof(ipn)); 620145510Sdarrenr 621145510Sdarrenr /* 622145510Sdarrenr * Check to see if this is the first NAT entry that will 623145510Sdarrenr * reference a particular rule and if so, flag it as such 624145510Sdarrenr * else just adjust the rule pointer to become a pointer to 625145510Sdarrenr * the other. We do this so we have a means later for tracking 626145510Sdarrenr * who is referencing us when we get back the real pointer 627145510Sdarrenr * in is_rule after doing the ioctl. 628145510Sdarrenr */ 629145510Sdarrenr nat = &in->ipn_nat; 630145510Sdarrenr if (nat->nat_fr != NULL) { 631145510Sdarrenr for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next) 632145510Sdarrenr if (in1->ipn_rule == nat->nat_fr) 633145510Sdarrenr break; 634145510Sdarrenr if (in1 == NULL) 635145510Sdarrenr nat->nat_flags |= SI_NEWFR; 636145510Sdarrenr else 637145510Sdarrenr nat->nat_fr = &in1->ipn_fr; 638145510Sdarrenr } 639145510Sdarrenr 640145510Sdarrenr /* 641145510Sdarrenr * Use a tail-queue type list (add things to the end).. 642145510Sdarrenr */ 643145510Sdarrenr in->ipn_next = NULL; 644145510Sdarrenr if (!ipnhead) 645145510Sdarrenr ipnhead = in; 646145510Sdarrenr if (ipntail) 647145510Sdarrenr ipntail->ipn_next = in; 648145510Sdarrenr ipntail = in; 649145510Sdarrenr } while (1); 650145510Sdarrenr 651145510Sdarrenr close(nfd); 652145510Sdarrenr nfd = -1; 653145510Sdarrenr 654145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 655145510Sdarrenr obj.ipfo_type = IPFOBJ_NATSAVE; 656145510Sdarrenr 657161357Sguido while ((in = ipnhead) != NULL) { 658145510Sdarrenr if (opts & OPT_VERBOSE) 659145510Sdarrenr printf("Loading new NAT table entry\n"); 660145510Sdarrenr nat = &in->ipn_nat; 661145510Sdarrenr if (nat->nat_flags & SI_NEWFR) { 662145510Sdarrenr if (opts & OPT_VERBOSE) 663145510Sdarrenr printf("Loading new filter rule\n"); 664145510Sdarrenr } 665145510Sdarrenr 666145510Sdarrenr obj.ipfo_ptr = in; 667145510Sdarrenr obj.ipfo_size = in->ipn_dsize; 668145510Sdarrenr if (!(opts & OPT_DONOTHING)) 669145510Sdarrenr if (ioctl(fd, SIOCSTPUT, &obj)) { 670145510Sdarrenr fprintf(stderr, "in=%p:", in); 671145510Sdarrenr perror("SIOCSTPUT"); 672145510Sdarrenr return 1; 673145510Sdarrenr } 674145510Sdarrenr 675145510Sdarrenr if (nat->nat_flags & SI_NEWFR) { 676145510Sdarrenr if (opts & OPT_VERBOSE) 677145510Sdarrenr printf("Real rule addr %p\n", nat->nat_fr); 678145510Sdarrenr for (in1 = in->ipn_next; in1; in1 = in1->ipn_next) 679145510Sdarrenr if (in1->ipn_rule == &in->ipn_fr) 680145510Sdarrenr in1->ipn_rule = nat->nat_fr; 681145510Sdarrenr } 682161357Sguido 683161357Sguido ipnhead = in->ipn_next; 684161357Sguido free(in); 685145510Sdarrenr } 686145510Sdarrenr 687145510Sdarrenr return 0; 688161357Sguido 689161357Sguidofreenathead: 690161357Sguido while ((in = ipnhead) != NULL) { 691161357Sguido ipnhead = in->ipn_next; 692161357Sguido free(in); 693161357Sguido } 694161357Sguido if (nfd != -1) 695161357Sguido close(nfd); 696161357Sguido return 1; 697145510Sdarrenr} 698145510Sdarrenr 699145510Sdarrenr 700145510Sdarrenrint writenat(fd, file) 701145510Sdarrenrint fd; 702145510Sdarrenrchar *file; 703145510Sdarrenr{ 704145510Sdarrenr nat_save_t *ipnp = NULL, *next = NULL; 705145510Sdarrenr ipfobj_t obj; 706145510Sdarrenr int nfd = -1; 707145510Sdarrenr natget_t ng; 708145510Sdarrenr 709145510Sdarrenr if (!file) 710145510Sdarrenr file = IPF_NATFILE; 711145510Sdarrenr 712145510Sdarrenr nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); 713145510Sdarrenr if (nfd == -1) { 714145510Sdarrenr fprintf(stderr, "%s ", file); 715145510Sdarrenr perror("nat:open"); 716145510Sdarrenr return 1; 717145510Sdarrenr } 718145510Sdarrenr 719145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 720145510Sdarrenr obj.ipfo_type = IPFOBJ_NATSAVE; 721145510Sdarrenr 722145510Sdarrenr do { 723145510Sdarrenr if (opts & OPT_VERBOSE) 724145510Sdarrenr printf("Getting nat from addr %p\n", ipnp); 725145510Sdarrenr ng.ng_ptr = next; 726145510Sdarrenr ng.ng_sz = 0; 727145510Sdarrenr if (ioctl(fd, SIOCSTGSZ, &ng)) { 728145510Sdarrenr perror("nat:SIOCSTGSZ"); 729145510Sdarrenr close(nfd); 730145510Sdarrenr if (ipnp != NULL) 731145510Sdarrenr free(ipnp); 732145510Sdarrenr return 1; 733145510Sdarrenr } 734145510Sdarrenr 735145510Sdarrenr if (opts & OPT_VERBOSE) 736145510Sdarrenr printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr); 737145510Sdarrenr 738145510Sdarrenr if (ng.ng_sz == 0) 739145510Sdarrenr break; 740145510Sdarrenr 741145510Sdarrenr if (!ipnp) 742145510Sdarrenr ipnp = malloc(ng.ng_sz); 743145510Sdarrenr else 744145510Sdarrenr ipnp = realloc((char *)ipnp, ng.ng_sz); 745145510Sdarrenr if (!ipnp) { 746145510Sdarrenr fprintf(stderr, 747145510Sdarrenr "malloc for %d bytes failed\n", ng.ng_sz); 748145510Sdarrenr break; 749145510Sdarrenr } 750145510Sdarrenr 751145510Sdarrenr bzero((char *)ipnp, ng.ng_sz); 752145510Sdarrenr obj.ipfo_size = ng.ng_sz; 753145510Sdarrenr obj.ipfo_ptr = ipnp; 754145510Sdarrenr ipnp->ipn_dsize = ng.ng_sz; 755145510Sdarrenr ipnp->ipn_next = next; 756145510Sdarrenr if (ioctl(fd, SIOCSTGET, &obj)) { 757145510Sdarrenr if (errno == ENOENT) 758145510Sdarrenr break; 759145510Sdarrenr perror("nat:SIOCSTGET"); 760145510Sdarrenr close(nfd); 761145510Sdarrenr free(ipnp); 762145510Sdarrenr return 1; 763145510Sdarrenr } 764145510Sdarrenr 765145510Sdarrenr if (opts & OPT_VERBOSE) 766145510Sdarrenr printf("Got nat next %p ipn_dsize %d ng_sz %d\n", 767145510Sdarrenr ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz); 768145510Sdarrenr if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) { 769145510Sdarrenr perror("nat:write"); 770145510Sdarrenr close(nfd); 771145510Sdarrenr free(ipnp); 772145510Sdarrenr return 1; 773145510Sdarrenr } 774145510Sdarrenr next = ipnp->ipn_next; 775145510Sdarrenr } while (ipnp && next); 776145510Sdarrenr if (ipnp != NULL) 777145510Sdarrenr free(ipnp); 778145510Sdarrenr close(nfd); 779145510Sdarrenr 780145510Sdarrenr return 0; 781145510Sdarrenr} 782145510Sdarrenr 783145510Sdarrenr 784145510Sdarrenrint writeall(dirname) 785145510Sdarrenrchar *dirname; 786145510Sdarrenr{ 787145510Sdarrenr int fd, devfd; 788145510Sdarrenr 789145510Sdarrenr if (!dirname) 790145510Sdarrenr dirname = IPF_SAVEDIR; 791145510Sdarrenr 792145510Sdarrenr if (chdir(dirname)) { 793145510Sdarrenr fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname); 794145510Sdarrenr perror("chdir(IPF_SAVEDIR)"); 795145510Sdarrenr return 1; 796145510Sdarrenr } 797145510Sdarrenr 798145510Sdarrenr fd = opendevice(NULL); 799145510Sdarrenr if (fd == -1) 800145510Sdarrenr return 1; 801145510Sdarrenr if (setlock(fd, 1)) { 802145510Sdarrenr close(fd); 803145510Sdarrenr return 1; 804145510Sdarrenr } 805145510Sdarrenr 806145510Sdarrenr devfd = opendevice(IPSTATE_NAME); 807145510Sdarrenr if (devfd == -1) 808145510Sdarrenr goto bad; 809145510Sdarrenr if (writestate(devfd, NULL)) 810145510Sdarrenr goto bad; 811145510Sdarrenr close(devfd); 812145510Sdarrenr 813145510Sdarrenr devfd = opendevice(IPNAT_NAME); 814145510Sdarrenr if (devfd == -1) 815145510Sdarrenr goto bad; 816145510Sdarrenr if (writenat(devfd, NULL)) 817145510Sdarrenr goto bad; 818145510Sdarrenr close(devfd); 819145510Sdarrenr 820145510Sdarrenr if (setlock(fd, 0)) { 821145510Sdarrenr close(fd); 822145510Sdarrenr return 1; 823145510Sdarrenr } 824145510Sdarrenr 825145510Sdarrenr close(fd); 826145510Sdarrenr return 0; 827145510Sdarrenr 828145510Sdarrenrbad: 829145510Sdarrenr setlock(fd, 0); 830145510Sdarrenr close(fd); 831145510Sdarrenr return 1; 832145510Sdarrenr} 833145510Sdarrenr 834145510Sdarrenr 835145510Sdarrenrint readall(dirname) 836145510Sdarrenrchar *dirname; 837145510Sdarrenr{ 838145510Sdarrenr int fd, devfd; 839145510Sdarrenr 840145510Sdarrenr if (!dirname) 841145510Sdarrenr dirname = IPF_SAVEDIR; 842145510Sdarrenr 843145510Sdarrenr if (chdir(dirname)) { 844145510Sdarrenr perror("chdir(IPF_SAVEDIR)"); 845145510Sdarrenr return 1; 846145510Sdarrenr } 847145510Sdarrenr 848145510Sdarrenr fd = opendevice(NULL); 849145510Sdarrenr if (fd == -1) 850145510Sdarrenr return 1; 851145510Sdarrenr if (setlock(fd, 1)) { 852145510Sdarrenr close(fd); 853145510Sdarrenr return 1; 854145510Sdarrenr } 855145510Sdarrenr 856145510Sdarrenr devfd = opendevice(IPSTATE_NAME); 857145510Sdarrenr if (devfd == -1) 858145510Sdarrenr return 1; 859145510Sdarrenr if (readstate(devfd, NULL)) 860145510Sdarrenr return 1; 861145510Sdarrenr close(devfd); 862145510Sdarrenr 863145510Sdarrenr devfd = opendevice(IPNAT_NAME); 864145510Sdarrenr if (devfd == -1) 865145510Sdarrenr return 1; 866145510Sdarrenr if (readnat(devfd, NULL)) 867145510Sdarrenr return 1; 868145510Sdarrenr close(devfd); 869145510Sdarrenr 870145510Sdarrenr if (setlock(fd, 0)) { 871145510Sdarrenr close(fd); 872145510Sdarrenr return 1; 873145510Sdarrenr } 874145510Sdarrenr 875145510Sdarrenr return 0; 876145510Sdarrenr} 877