ipfs.c revision 145519
1145519Sdarrenr/* $FreeBSD: head/contrib/ipfilter/tools/ipfs.c 145519 2005-04-25 18:20:15Z darrenr $ */ 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" 44145510Sdarrenr#include "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"); 463145510Sdarrenr close(sfd); 464145510Sdarrenr return 1; 465145510Sdarrenr } 466145510Sdarrenr if (i == 0) 467145510Sdarrenr break; 468145510Sdarrenr if (i != sizeof(ips)) { 469145510Sdarrenr fprintf(stderr, "state:incomplete read: %d != %d\n", 470145510Sdarrenr i, (int)sizeof(ips)); 471145510Sdarrenr close(sfd); 472145510Sdarrenr return 1; 473145510Sdarrenr } 474145510Sdarrenr is = (ipstate_save_t *)malloc(sizeof(*is)); 475145510Sdarrenr if(!is) { 476145510Sdarrenr fprintf(stderr, "malloc failed\n"); 477145510Sdarrenr return 1; 478145510Sdarrenr } 479145510Sdarrenr 480145510Sdarrenr bcopy((char *)&ips, (char *)is, sizeof(ips)); 481145510Sdarrenr 482145510Sdarrenr /* 483145510Sdarrenr * Check to see if this is the first state entry that will 484145510Sdarrenr * reference a particular rule and if so, flag it as such 485145510Sdarrenr * else just adjust the rule pointer to become a pointer to 486145510Sdarrenr * the other. We do this so we have a means later for tracking 487145510Sdarrenr * who is referencing us when we get back the real pointer 488145510Sdarrenr * in is_rule after doing the ioctl. 489145510Sdarrenr */ 490145510Sdarrenr for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next) 491145510Sdarrenr if (is1->ips_rule == is->ips_rule) 492145510Sdarrenr break; 493145510Sdarrenr if (is1 == NULL) 494145510Sdarrenr is->ips_is.is_flags |= SI_NEWFR; 495145510Sdarrenr else 496145510Sdarrenr is->ips_rule = (void *)&is1->ips_rule; 497145510Sdarrenr 498145510Sdarrenr /* 499145510Sdarrenr * Use a tail-queue type list (add things to the end).. 500145510Sdarrenr */ 501145510Sdarrenr is->ips_next = NULL; 502145510Sdarrenr if (!ipshead) 503145510Sdarrenr ipshead = is; 504145510Sdarrenr if (ipstail) 505145510Sdarrenr ipstail->ips_next = is; 506145510Sdarrenr ipstail = is; 507145510Sdarrenr } while (1); 508145510Sdarrenr 509145510Sdarrenr close(sfd); 510145510Sdarrenr 511145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 512145510Sdarrenr obj.ipfo_size = sizeof(*is); 513145510Sdarrenr obj.ipfo_type = IPFOBJ_STATESAVE; 514145510Sdarrenr 515145510Sdarrenr for (is = ipshead; is; is = is->ips_next) { 516145510Sdarrenr if (opts & OPT_VERBOSE) 517145510Sdarrenr printf("Loading new state table entry\n"); 518145510Sdarrenr if (is->ips_is.is_flags & SI_NEWFR) { 519145510Sdarrenr if (opts & OPT_VERBOSE) 520145510Sdarrenr printf("Loading new filter rule\n"); 521145510Sdarrenr } 522145510Sdarrenr 523145510Sdarrenr obj.ipfo_ptr = is; 524145510Sdarrenr if (!(opts & OPT_DONOTHING)) 525145510Sdarrenr if (ioctl(fd, SIOCSTPUT, &obj)) { 526145510Sdarrenr perror("SIOCSTPUT"); 527145510Sdarrenr return 1; 528145510Sdarrenr } 529145510Sdarrenr 530145510Sdarrenr if (is->ips_is.is_flags & SI_NEWFR) { 531145510Sdarrenr if (opts & OPT_VERBOSE) 532145510Sdarrenr printf("Real rule addr %p\n", is->ips_rule); 533145510Sdarrenr for (is1 = is->ips_next; is1; is1 = is1->ips_next) 534145510Sdarrenr if (is1->ips_rule == (frentry_t *)&is->ips_rule) 535145510Sdarrenr is1->ips_rule = is->ips_rule; 536145510Sdarrenr } 537145510Sdarrenr } 538145510Sdarrenr 539145510Sdarrenr return 0; 540145510Sdarrenr} 541145510Sdarrenr 542145510Sdarrenr 543145510Sdarrenrint readnat(fd, file) 544145510Sdarrenrint fd; 545145510Sdarrenrchar *file; 546145510Sdarrenr{ 547145510Sdarrenr nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL; 548145510Sdarrenr ipfobj_t obj; 549145510Sdarrenr int nfd, i; 550145510Sdarrenr nat_t *nat; 551145510Sdarrenr char *s; 552145510Sdarrenr int n; 553145510Sdarrenr 554145510Sdarrenr nfd = -1; 555145510Sdarrenr in = NULL; 556145510Sdarrenr ipnhead = NULL; 557145510Sdarrenr ipntail = NULL; 558145510Sdarrenr 559145510Sdarrenr if (!file) 560145510Sdarrenr file = IPF_NATFILE; 561145510Sdarrenr 562145510Sdarrenr nfd = open(file, O_RDONLY); 563145510Sdarrenr if (nfd == -1) { 564145510Sdarrenr fprintf(stderr, "%s ", file); 565145510Sdarrenr perror("nat:open"); 566145510Sdarrenr return 1; 567145510Sdarrenr } 568145510Sdarrenr 569145510Sdarrenr bzero((char *)&ipn, sizeof(ipn)); 570145510Sdarrenr 571145510Sdarrenr /* 572145510Sdarrenr * 1. Read all state information in. 573145510Sdarrenr */ 574145510Sdarrenr do { 575145510Sdarrenr i = read(nfd, &ipn, sizeof(ipn)); 576145510Sdarrenr if (i == -1) { 577145510Sdarrenr perror("read"); 578145510Sdarrenr close(nfd); 579145510Sdarrenr return 1; 580145510Sdarrenr } 581145510Sdarrenr if (i == 0) 582145510Sdarrenr break; 583145510Sdarrenr if (i != sizeof(ipn)) { 584145510Sdarrenr fprintf(stderr, "nat:incomplete read: %d != %d\n", 585145510Sdarrenr i, (int)sizeof(ipn)); 586145510Sdarrenr close(nfd); 587145510Sdarrenr return 1; 588145510Sdarrenr } 589145510Sdarrenr 590145510Sdarrenr in = (nat_save_t *)malloc(ipn.ipn_dsize); 591145510Sdarrenr if (!in) 592145510Sdarrenr break; 593145510Sdarrenr 594145510Sdarrenr if (ipn.ipn_dsize > sizeof(ipn)) { 595145510Sdarrenr n = ipn.ipn_dsize - sizeof(ipn); 596145510Sdarrenr if (n > 0) { 597145510Sdarrenr s = in->ipn_data + sizeof(in->ipn_data); 598145510Sdarrenr i = read(nfd, s, n); 599145510Sdarrenr if (i == 0) 600145510Sdarrenr break; 601145510Sdarrenr if (i != n) { 602145510Sdarrenr fprintf(stderr, 603145510Sdarrenr "nat:incomplete read: %d != %d\n", 604145510Sdarrenr i, n); 605145510Sdarrenr close(nfd); 606145510Sdarrenr return 1; 607145510Sdarrenr } 608145510Sdarrenr } 609145510Sdarrenr } 610145510Sdarrenr bcopy((char *)&ipn, (char *)in, sizeof(ipn)); 611145510Sdarrenr 612145510Sdarrenr /* 613145510Sdarrenr * Check to see if this is the first NAT entry that will 614145510Sdarrenr * reference a particular rule and if so, flag it as such 615145510Sdarrenr * else just adjust the rule pointer to become a pointer to 616145510Sdarrenr * the other. We do this so we have a means later for tracking 617145510Sdarrenr * who is referencing us when we get back the real pointer 618145510Sdarrenr * in is_rule after doing the ioctl. 619145510Sdarrenr */ 620145510Sdarrenr nat = &in->ipn_nat; 621145510Sdarrenr if (nat->nat_fr != NULL) { 622145510Sdarrenr for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next) 623145510Sdarrenr if (in1->ipn_rule == nat->nat_fr) 624145510Sdarrenr break; 625145510Sdarrenr if (in1 == NULL) 626145510Sdarrenr nat->nat_flags |= SI_NEWFR; 627145510Sdarrenr else 628145510Sdarrenr nat->nat_fr = &in1->ipn_fr; 629145510Sdarrenr } 630145510Sdarrenr 631145510Sdarrenr /* 632145510Sdarrenr * Use a tail-queue type list (add things to the end).. 633145510Sdarrenr */ 634145510Sdarrenr in->ipn_next = NULL; 635145510Sdarrenr if (!ipnhead) 636145510Sdarrenr ipnhead = in; 637145510Sdarrenr if (ipntail) 638145510Sdarrenr ipntail->ipn_next = in; 639145510Sdarrenr ipntail = in; 640145510Sdarrenr } while (1); 641145510Sdarrenr 642145510Sdarrenr close(nfd); 643145510Sdarrenr nfd = -1; 644145510Sdarrenr 645145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 646145510Sdarrenr obj.ipfo_type = IPFOBJ_NATSAVE; 647145510Sdarrenr 648145510Sdarrenr for (in = ipnhead; in; in = in->ipn_next) { 649145510Sdarrenr if (opts & OPT_VERBOSE) 650145510Sdarrenr printf("Loading new NAT table entry\n"); 651145510Sdarrenr nat = &in->ipn_nat; 652145510Sdarrenr if (nat->nat_flags & SI_NEWFR) { 653145510Sdarrenr if (opts & OPT_VERBOSE) 654145510Sdarrenr printf("Loading new filter rule\n"); 655145510Sdarrenr } 656145510Sdarrenr 657145510Sdarrenr obj.ipfo_ptr = in; 658145510Sdarrenr obj.ipfo_size = in->ipn_dsize; 659145510Sdarrenr if (!(opts & OPT_DONOTHING)) 660145510Sdarrenr if (ioctl(fd, SIOCSTPUT, &obj)) { 661145510Sdarrenr fprintf(stderr, "in=%p:", in); 662145510Sdarrenr perror("SIOCSTPUT"); 663145510Sdarrenr return 1; 664145510Sdarrenr } 665145510Sdarrenr 666145510Sdarrenr if (nat->nat_flags & SI_NEWFR) { 667145510Sdarrenr if (opts & OPT_VERBOSE) 668145510Sdarrenr printf("Real rule addr %p\n", nat->nat_fr); 669145510Sdarrenr for (in1 = in->ipn_next; in1; in1 = in1->ipn_next) 670145510Sdarrenr if (in1->ipn_rule == &in->ipn_fr) 671145510Sdarrenr in1->ipn_rule = nat->nat_fr; 672145510Sdarrenr } 673145510Sdarrenr } 674145510Sdarrenr 675145510Sdarrenr return 0; 676145510Sdarrenr} 677145510Sdarrenr 678145510Sdarrenr 679145510Sdarrenrint writenat(fd, file) 680145510Sdarrenrint fd; 681145510Sdarrenrchar *file; 682145510Sdarrenr{ 683145510Sdarrenr nat_save_t *ipnp = NULL, *next = NULL; 684145510Sdarrenr ipfobj_t obj; 685145510Sdarrenr int nfd = -1; 686145510Sdarrenr natget_t ng; 687145510Sdarrenr 688145510Sdarrenr if (!file) 689145510Sdarrenr file = IPF_NATFILE; 690145510Sdarrenr 691145510Sdarrenr nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); 692145510Sdarrenr if (nfd == -1) { 693145510Sdarrenr fprintf(stderr, "%s ", file); 694145510Sdarrenr perror("nat:open"); 695145510Sdarrenr return 1; 696145510Sdarrenr } 697145510Sdarrenr 698145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 699145510Sdarrenr obj.ipfo_type = IPFOBJ_NATSAVE; 700145510Sdarrenr 701145510Sdarrenr do { 702145510Sdarrenr if (opts & OPT_VERBOSE) 703145510Sdarrenr printf("Getting nat from addr %p\n", ipnp); 704145510Sdarrenr ng.ng_ptr = next; 705145510Sdarrenr ng.ng_sz = 0; 706145510Sdarrenr if (ioctl(fd, SIOCSTGSZ, &ng)) { 707145510Sdarrenr perror("nat:SIOCSTGSZ"); 708145510Sdarrenr close(nfd); 709145510Sdarrenr if (ipnp != NULL) 710145510Sdarrenr free(ipnp); 711145510Sdarrenr return 1; 712145510Sdarrenr } 713145510Sdarrenr 714145510Sdarrenr if (opts & OPT_VERBOSE) 715145510Sdarrenr printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr); 716145510Sdarrenr 717145510Sdarrenr if (ng.ng_sz == 0) 718145510Sdarrenr break; 719145510Sdarrenr 720145510Sdarrenr if (!ipnp) 721145510Sdarrenr ipnp = malloc(ng.ng_sz); 722145510Sdarrenr else 723145510Sdarrenr ipnp = realloc((char *)ipnp, ng.ng_sz); 724145510Sdarrenr if (!ipnp) { 725145510Sdarrenr fprintf(stderr, 726145510Sdarrenr "malloc for %d bytes failed\n", ng.ng_sz); 727145510Sdarrenr break; 728145510Sdarrenr } 729145510Sdarrenr 730145510Sdarrenr bzero((char *)ipnp, ng.ng_sz); 731145510Sdarrenr obj.ipfo_size = ng.ng_sz; 732145510Sdarrenr obj.ipfo_ptr = ipnp; 733145510Sdarrenr ipnp->ipn_dsize = ng.ng_sz; 734145510Sdarrenr ipnp->ipn_next = next; 735145510Sdarrenr if (ioctl(fd, SIOCSTGET, &obj)) { 736145510Sdarrenr if (errno == ENOENT) 737145510Sdarrenr break; 738145510Sdarrenr perror("nat:SIOCSTGET"); 739145510Sdarrenr close(nfd); 740145510Sdarrenr free(ipnp); 741145510Sdarrenr return 1; 742145510Sdarrenr } 743145510Sdarrenr 744145510Sdarrenr if (opts & OPT_VERBOSE) 745145510Sdarrenr printf("Got nat next %p ipn_dsize %d ng_sz %d\n", 746145510Sdarrenr ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz); 747145510Sdarrenr if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) { 748145510Sdarrenr perror("nat:write"); 749145510Sdarrenr close(nfd); 750145510Sdarrenr free(ipnp); 751145510Sdarrenr return 1; 752145510Sdarrenr } 753145510Sdarrenr next = ipnp->ipn_next; 754145510Sdarrenr } while (ipnp && next); 755145510Sdarrenr if (ipnp != NULL) 756145510Sdarrenr free(ipnp); 757145510Sdarrenr close(nfd); 758145510Sdarrenr 759145510Sdarrenr return 0; 760145510Sdarrenr} 761145510Sdarrenr 762145510Sdarrenr 763145510Sdarrenrint writeall(dirname) 764145510Sdarrenrchar *dirname; 765145510Sdarrenr{ 766145510Sdarrenr int fd, devfd; 767145510Sdarrenr 768145510Sdarrenr if (!dirname) 769145510Sdarrenr dirname = IPF_SAVEDIR; 770145510Sdarrenr 771145510Sdarrenr if (chdir(dirname)) { 772145510Sdarrenr fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname); 773145510Sdarrenr perror("chdir(IPF_SAVEDIR)"); 774145510Sdarrenr return 1; 775145510Sdarrenr } 776145510Sdarrenr 777145510Sdarrenr fd = opendevice(NULL); 778145510Sdarrenr if (fd == -1) 779145510Sdarrenr return 1; 780145510Sdarrenr if (setlock(fd, 1)) { 781145510Sdarrenr close(fd); 782145510Sdarrenr return 1; 783145510Sdarrenr } 784145510Sdarrenr 785145510Sdarrenr devfd = opendevice(IPSTATE_NAME); 786145510Sdarrenr if (devfd == -1) 787145510Sdarrenr goto bad; 788145510Sdarrenr if (writestate(devfd, NULL)) 789145510Sdarrenr goto bad; 790145510Sdarrenr close(devfd); 791145510Sdarrenr 792145510Sdarrenr devfd = opendevice(IPNAT_NAME); 793145510Sdarrenr if (devfd == -1) 794145510Sdarrenr goto bad; 795145510Sdarrenr if (writenat(devfd, NULL)) 796145510Sdarrenr goto bad; 797145510Sdarrenr close(devfd); 798145510Sdarrenr 799145510Sdarrenr if (setlock(fd, 0)) { 800145510Sdarrenr close(fd); 801145510Sdarrenr return 1; 802145510Sdarrenr } 803145510Sdarrenr 804145510Sdarrenr close(fd); 805145510Sdarrenr return 0; 806145510Sdarrenr 807145510Sdarrenrbad: 808145510Sdarrenr setlock(fd, 0); 809145510Sdarrenr close(fd); 810145510Sdarrenr return 1; 811145510Sdarrenr} 812145510Sdarrenr 813145510Sdarrenr 814145510Sdarrenrint readall(dirname) 815145510Sdarrenrchar *dirname; 816145510Sdarrenr{ 817145510Sdarrenr int fd, devfd; 818145510Sdarrenr 819145510Sdarrenr if (!dirname) 820145510Sdarrenr dirname = IPF_SAVEDIR; 821145510Sdarrenr 822145510Sdarrenr if (chdir(dirname)) { 823145510Sdarrenr perror("chdir(IPF_SAVEDIR)"); 824145510Sdarrenr return 1; 825145510Sdarrenr } 826145510Sdarrenr 827145510Sdarrenr fd = opendevice(NULL); 828145510Sdarrenr if (fd == -1) 829145510Sdarrenr return 1; 830145510Sdarrenr if (setlock(fd, 1)) { 831145510Sdarrenr close(fd); 832145510Sdarrenr return 1; 833145510Sdarrenr } 834145510Sdarrenr 835145510Sdarrenr devfd = opendevice(IPSTATE_NAME); 836145510Sdarrenr if (devfd == -1) 837145510Sdarrenr return 1; 838145510Sdarrenr if (readstate(devfd, NULL)) 839145510Sdarrenr return 1; 840145510Sdarrenr close(devfd); 841145510Sdarrenr 842145510Sdarrenr devfd = opendevice(IPNAT_NAME); 843145510Sdarrenr if (devfd == -1) 844145510Sdarrenr return 1; 845145510Sdarrenr if (readnat(devfd, NULL)) 846145510Sdarrenr return 1; 847145510Sdarrenr close(devfd); 848145510Sdarrenr 849145510Sdarrenr if (setlock(fd, 0)) { 850145510Sdarrenr close(fd); 851145510Sdarrenr return 1; 852145510Sdarrenr } 853145510Sdarrenr 854145510Sdarrenr return 0; 855145510Sdarrenr} 856