1145519Sdarrenr/* $FreeBSD$ */ 2145510Sdarrenr 3145510Sdarrenr/* 4255332Scy * Copyright (C) 2012 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) 47255332Scystatic const char rcsid[] = "@(#)$Id$"; 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) 103255332Scy char *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 } 136170268Sdarrenr if (!strncmp(ips.ips_is.is_ifname[2], ifs, olen + 1)) { 137170268Sdarrenr strcpy(ips.ips_is.is_ifname[2], s); 138170268Sdarrenr rw = 1; 139170268Sdarrenr } 140170268Sdarrenr if (!strncmp(ips.ips_is.is_ifname[3], ifs, olen + 1)) { 141170268Sdarrenr strcpy(ips.ips_is.is_ifname[3], s); 142170268Sdarrenr rw = 1; 143170268Sdarrenr } 144145510Sdarrenr if (rw == 1) { 145145510Sdarrenr if (lseek(fd, pos, SEEK_SET) != pos) { 146145510Sdarrenr perror("lseek"); 147145510Sdarrenr exit(1); 148145510Sdarrenr } 149145510Sdarrenr if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) { 150145510Sdarrenr perror("write"); 151145510Sdarrenr exit(1); 152145510Sdarrenr } 153145510Sdarrenr } 154145510Sdarrenr pos = lseek(fd, 0, SEEK_CUR); 155145510Sdarrenr } 156145510Sdarrenr close(fd); 157145510Sdarrenr 158145510Sdarrenr return 0; 159145510Sdarrenr} 160145510Sdarrenr 161145510Sdarrenr 162145510Sdarrenr/* 163145510Sdarrenr * Change interface names in NAT information saved out to disk. 164145510Sdarrenr */ 165145510Sdarrenrint changenatif(ifs, fname) 166255332Scy char *ifs, *fname; 167145510Sdarrenr{ 168145510Sdarrenr int fd, olen, nlen, rw; 169145510Sdarrenr nat_save_t ipn; 170145510Sdarrenr nat_t *nat; 171145510Sdarrenr off_t pos; 172145510Sdarrenr char *s; 173145510Sdarrenr 174145510Sdarrenr s = strchr(ifs, ','); 175145510Sdarrenr if (!s) 176145510Sdarrenr usage(); 177145510Sdarrenr *s++ = '\0'; 178145510Sdarrenr nlen = strlen(s); 179145510Sdarrenr olen = strlen(ifs); 180145510Sdarrenr nat = &ipn.ipn_nat; 181145510Sdarrenr if (nlen >= sizeof(nat->nat_ifnames[0]) || 182145510Sdarrenr olen >= sizeof(nat->nat_ifnames[0])) 183145510Sdarrenr usage(); 184145510Sdarrenr 185145510Sdarrenr fd = open(fname, O_RDWR); 186145510Sdarrenr if (fd == -1) { 187145510Sdarrenr perror("open"); 188145510Sdarrenr exit(1); 189145510Sdarrenr } 190145510Sdarrenr 191145510Sdarrenr for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) { 192145510Sdarrenr rw = 0; 193145510Sdarrenr if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) { 194145510Sdarrenr strcpy(nat->nat_ifnames[0], s); 195145510Sdarrenr rw = 1; 196145510Sdarrenr } 197145510Sdarrenr if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) { 198145510Sdarrenr strcpy(nat->nat_ifnames[1], s); 199145510Sdarrenr rw = 1; 200145510Sdarrenr } 201145510Sdarrenr if (rw == 1) { 202145510Sdarrenr if (lseek(fd, pos, SEEK_SET) != pos) { 203145510Sdarrenr perror("lseek"); 204145510Sdarrenr exit(1); 205145510Sdarrenr } 206145510Sdarrenr if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) { 207145510Sdarrenr perror("write"); 208145510Sdarrenr exit(1); 209145510Sdarrenr } 210145510Sdarrenr } 211145510Sdarrenr pos = lseek(fd, 0, SEEK_CUR); 212145510Sdarrenr } 213145510Sdarrenr close(fd); 214145510Sdarrenr 215145510Sdarrenr return 0; 216145510Sdarrenr} 217145510Sdarrenr 218145510Sdarrenr 219145510Sdarrenrint main(argc,argv) 220255332Scy int argc; 221255332Scy char *argv[]; 222145510Sdarrenr{ 223145510Sdarrenr int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0; 224145510Sdarrenr char *dirname = NULL, *filename = NULL, *ifs = NULL; 225145510Sdarrenr 226145510Sdarrenr progname = argv[0]; 227170268Sdarrenr while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1) 228145510Sdarrenr switch (c) 229145510Sdarrenr { 230145510Sdarrenr case 'd' : 231145510Sdarrenr if ((set == 0) && !dirname && !filename) 232145510Sdarrenr dirname = optarg; 233145510Sdarrenr else 234145510Sdarrenr usage(); 235145510Sdarrenr break; 236145510Sdarrenr case 'f' : 237145510Sdarrenr if ((set != 0) && !dirname && !filename) 238145510Sdarrenr filename = optarg; 239145510Sdarrenr else 240145510Sdarrenr usage(); 241145510Sdarrenr break; 242145510Sdarrenr case 'i' : 243145510Sdarrenr ifs = optarg; 244145510Sdarrenr set = 1; 245145510Sdarrenr break; 246145510Sdarrenr case 'l' : 247145510Sdarrenr if (filename || dirname || set) 248145510Sdarrenr usage(); 249145510Sdarrenr lock = 1; 250145510Sdarrenr set = 1; 251145510Sdarrenr break; 252145510Sdarrenr case 'n' : 253145510Sdarrenr opts |= OPT_DONOTHING; 254145510Sdarrenr break; 255145510Sdarrenr case 'N' : 256145510Sdarrenr if ((ns >= 0) || dirname || (rw != -1) || set) 257145510Sdarrenr usage(); 258145510Sdarrenr ns = 0; 259145510Sdarrenr set = 1; 260145510Sdarrenr break; 261145510Sdarrenr case 'r' : 262145510Sdarrenr if (dirname || (rw != -1) || (ns == -1)) 263145510Sdarrenr usage(); 264145510Sdarrenr rw = 0; 265145510Sdarrenr set = 1; 266145510Sdarrenr break; 267145510Sdarrenr case 'R' : 268145510Sdarrenr rw = 2; 269145510Sdarrenr set = 1; 270145510Sdarrenr break; 271145510Sdarrenr case 'S' : 272145510Sdarrenr if ((ns >= 0) || dirname || (rw != -1) || set) 273145510Sdarrenr usage(); 274145510Sdarrenr ns = 1; 275145510Sdarrenr set = 1; 276145510Sdarrenr break; 277145510Sdarrenr case 'u' : 278145510Sdarrenr if (filename || dirname || set) 279145510Sdarrenr usage(); 280145510Sdarrenr lock = 0; 281145510Sdarrenr set = 1; 282145510Sdarrenr break; 283145510Sdarrenr case 'v' : 284145510Sdarrenr opts |= OPT_VERBOSE; 285145510Sdarrenr break; 286145510Sdarrenr case 'w' : 287145510Sdarrenr if (dirname || (rw != -1) || (ns == -1)) 288145510Sdarrenr usage(); 289145510Sdarrenr rw = 1; 290145510Sdarrenr set = 1; 291145510Sdarrenr break; 292145510Sdarrenr case 'W' : 293145510Sdarrenr rw = 3; 294145510Sdarrenr set = 1; 295145510Sdarrenr break; 296145510Sdarrenr case '?' : 297145510Sdarrenr default : 298145510Sdarrenr usage(); 299145510Sdarrenr } 300145510Sdarrenr 301145510Sdarrenr if (ifs) { 302145510Sdarrenr if (!filename || ns < 0) 303145510Sdarrenr usage(); 304145510Sdarrenr if (ns == 0) 305145510Sdarrenr return changenatif(ifs, filename); 306145510Sdarrenr else 307145510Sdarrenr return changestateif(ifs, filename); 308145510Sdarrenr } 309145510Sdarrenr 310145510Sdarrenr if ((ns >= 0) || (lock >= 0)) { 311145510Sdarrenr if (lock >= 0) 312145510Sdarrenr devfd = opendevice(NULL); 313145510Sdarrenr else if (ns >= 0) { 314145510Sdarrenr if (ns == 1) 315145510Sdarrenr devfd = opendevice(IPSTATE_NAME); 316145510Sdarrenr else if (ns == 0) 317145510Sdarrenr devfd = opendevice(IPNAT_NAME); 318145510Sdarrenr } 319145510Sdarrenr if (devfd == -1) 320145510Sdarrenr exit(1); 321145510Sdarrenr } 322145510Sdarrenr 323145510Sdarrenr if (lock >= 0) 324145510Sdarrenr err = setlock(devfd, lock); 325145510Sdarrenr else if (rw >= 0) { 326145510Sdarrenr if (rw & 1) { /* WRITE */ 327145510Sdarrenr if (rw & 2) 328145510Sdarrenr err = writeall(dirname); 329145510Sdarrenr else { 330145510Sdarrenr if (ns == 0) 331145510Sdarrenr err = writenat(devfd, filename); 332145510Sdarrenr else if (ns == 1) 333145510Sdarrenr err = writestate(devfd, filename); 334145510Sdarrenr } 335145510Sdarrenr } else { 336145510Sdarrenr if (rw & 2) 337145510Sdarrenr err = readall(dirname); 338145510Sdarrenr else { 339145510Sdarrenr if (ns == 0) 340145510Sdarrenr err = readnat(devfd, filename); 341145510Sdarrenr else if (ns == 1) 342145510Sdarrenr err = readstate(devfd, filename); 343145510Sdarrenr } 344145510Sdarrenr } 345145510Sdarrenr } 346145510Sdarrenr return err; 347145510Sdarrenr} 348145510Sdarrenr 349145510Sdarrenr 350145510Sdarrenrint opendevice(ipfdev) 351255332Scy char *ipfdev; 352145510Sdarrenr{ 353145510Sdarrenr int fd = -1; 354145510Sdarrenr 355145510Sdarrenr if (opts & OPT_DONOTHING) 356145510Sdarrenr return -2; 357145510Sdarrenr 358145510Sdarrenr if (!ipfdev) 359145510Sdarrenr ipfdev = IPL_NAME; 360145510Sdarrenr 361145510Sdarrenr if ((fd = open(ipfdev, O_RDWR)) == -1) 362145510Sdarrenr if ((fd = open(ipfdev, O_RDONLY)) == -1) 363145510Sdarrenr perror("open device"); 364145510Sdarrenr return fd; 365145510Sdarrenr} 366145510Sdarrenr 367145510Sdarrenr 368145510Sdarrenrvoid closedevice(fd) 369255332Scy int fd; 370145510Sdarrenr{ 371145510Sdarrenr close(fd); 372145510Sdarrenr} 373145510Sdarrenr 374145510Sdarrenr 375145510Sdarrenrint setlock(fd, lock) 376255332Scy int fd, lock; 377145510Sdarrenr{ 378145510Sdarrenr if (opts & OPT_VERBOSE) 379145510Sdarrenr printf("Turn lock %s\n", lock ? "on" : "off"); 380145510Sdarrenr if (!(opts & OPT_DONOTHING)) { 381145510Sdarrenr if (ioctl(fd, SIOCSTLCK, &lock) == -1) { 382145510Sdarrenr perror("SIOCSTLCK"); 383145510Sdarrenr return 1; 384145510Sdarrenr } 385145510Sdarrenr if (opts & OPT_VERBOSE) 386145510Sdarrenr printf("Lock now %s\n", lock ? "on" : "off"); 387145510Sdarrenr } 388145510Sdarrenr return 0; 389145510Sdarrenr} 390145510Sdarrenr 391145510Sdarrenr 392145510Sdarrenrint writestate(fd, file) 393255332Scy int fd; 394255332Scy char *file; 395145510Sdarrenr{ 396145510Sdarrenr ipstate_save_t ips, *ipsp; 397145510Sdarrenr ipfobj_t obj; 398145510Sdarrenr int wfd = -1; 399145510Sdarrenr 400145510Sdarrenr if (!file) 401145510Sdarrenr file = IPF_STATEFILE; 402145510Sdarrenr 403145510Sdarrenr wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); 404145510Sdarrenr if (wfd == -1) { 405145510Sdarrenr fprintf(stderr, "%s ", file); 406145510Sdarrenr perror("state:open"); 407145510Sdarrenr return 1; 408145510Sdarrenr } 409145510Sdarrenr 410145510Sdarrenr ipsp = &ips; 411145510Sdarrenr bzero((char *)&obj, sizeof(obj)); 412145510Sdarrenr bzero((char *)ipsp, sizeof(ips)); 413145510Sdarrenr 414145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 415145510Sdarrenr obj.ipfo_size = sizeof(*ipsp); 416145510Sdarrenr obj.ipfo_type = IPFOBJ_STATESAVE; 417145510Sdarrenr obj.ipfo_ptr = ipsp; 418145510Sdarrenr 419145510Sdarrenr do { 420145510Sdarrenr 421145510Sdarrenr if (opts & OPT_VERBOSE) 422145510Sdarrenr printf("Getting state from addr %p\n", ips.ips_next); 423145510Sdarrenr if (ioctl(fd, SIOCSTGET, &obj)) { 424145510Sdarrenr if (errno == ENOENT) 425145510Sdarrenr break; 426145510Sdarrenr perror("state:SIOCSTGET"); 427145510Sdarrenr close(wfd); 428145510Sdarrenr return 1; 429145510Sdarrenr } 430145510Sdarrenr if (opts & OPT_VERBOSE) 431145510Sdarrenr printf("Got state next %p\n", ips.ips_next); 432145510Sdarrenr if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) { 433145510Sdarrenr perror("state:write"); 434145510Sdarrenr close(wfd); 435145510Sdarrenr return 1; 436145510Sdarrenr } 437145510Sdarrenr } while (ips.ips_next != NULL); 438145510Sdarrenr close(wfd); 439145510Sdarrenr 440145510Sdarrenr return 0; 441145510Sdarrenr} 442145510Sdarrenr 443145510Sdarrenr 444145510Sdarrenrint readstate(fd, file) 445255332Scy int fd; 446255332Scy char *file; 447145510Sdarrenr{ 448145510Sdarrenr ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL; 449145510Sdarrenr int sfd = -1, i; 450145510Sdarrenr ipfobj_t obj; 451145510Sdarrenr 452145510Sdarrenr if (!file) 453145510Sdarrenr file = IPF_STATEFILE; 454145510Sdarrenr 455145510Sdarrenr sfd = open(file, O_RDONLY, 0600); 456145510Sdarrenr if (sfd == -1) { 457145510Sdarrenr fprintf(stderr, "%s ", file); 458145510Sdarrenr perror("open"); 459145510Sdarrenr return 1; 460145510Sdarrenr } 461145510Sdarrenr 462145510Sdarrenr bzero((char *)&ips, sizeof(ips)); 463145510Sdarrenr 464145510Sdarrenr /* 465145510Sdarrenr * 1. Read all state information in. 466145510Sdarrenr */ 467145510Sdarrenr do { 468145510Sdarrenr i = read(sfd, &ips, sizeof(ips)); 469145510Sdarrenr if (i == -1) { 470145510Sdarrenr perror("read"); 471161357Sguido goto freeipshead; 472145510Sdarrenr } 473145510Sdarrenr if (i == 0) 474145510Sdarrenr break; 475145510Sdarrenr if (i != sizeof(ips)) { 476145510Sdarrenr fprintf(stderr, "state:incomplete read: %d != %d\n", 477145510Sdarrenr i, (int)sizeof(ips)); 478161357Sguido goto freeipshead; 479145510Sdarrenr } 480145510Sdarrenr is = (ipstate_save_t *)malloc(sizeof(*is)); 481161357Sguido if (is == NULL) { 482145510Sdarrenr fprintf(stderr, "malloc failed\n"); 483161357Sguido goto freeipshead; 484145510Sdarrenr } 485145510Sdarrenr 486145510Sdarrenr bcopy((char *)&ips, (char *)is, sizeof(ips)); 487145510Sdarrenr 488145510Sdarrenr /* 489145510Sdarrenr * Check to see if this is the first state entry that will 490145510Sdarrenr * reference a particular rule and if so, flag it as such 491145510Sdarrenr * else just adjust the rule pointer to become a pointer to 492145510Sdarrenr * the other. We do this so we have a means later for tracking 493145510Sdarrenr * who is referencing us when we get back the real pointer 494145510Sdarrenr * in is_rule after doing the ioctl. 495145510Sdarrenr */ 496145510Sdarrenr for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next) 497145510Sdarrenr if (is1->ips_rule == is->ips_rule) 498145510Sdarrenr break; 499145510Sdarrenr if (is1 == NULL) 500145510Sdarrenr is->ips_is.is_flags |= SI_NEWFR; 501145510Sdarrenr else 502145510Sdarrenr is->ips_rule = (void *)&is1->ips_rule; 503145510Sdarrenr 504145510Sdarrenr /* 505145510Sdarrenr * Use a tail-queue type list (add things to the end).. 506145510Sdarrenr */ 507145510Sdarrenr is->ips_next = NULL; 508145510Sdarrenr if (!ipshead) 509145510Sdarrenr ipshead = is; 510145510Sdarrenr if (ipstail) 511145510Sdarrenr ipstail->ips_next = is; 512145510Sdarrenr ipstail = is; 513145510Sdarrenr } while (1); 514145510Sdarrenr 515145510Sdarrenr close(sfd); 516145510Sdarrenr 517145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 518145510Sdarrenr obj.ipfo_size = sizeof(*is); 519145510Sdarrenr obj.ipfo_type = IPFOBJ_STATESAVE; 520145510Sdarrenr 521161357Sguido while ((is = ipshead) != NULL) { 522145510Sdarrenr if (opts & OPT_VERBOSE) 523145510Sdarrenr printf("Loading new state table entry\n"); 524145510Sdarrenr if (is->ips_is.is_flags & SI_NEWFR) { 525145510Sdarrenr if (opts & OPT_VERBOSE) 526145510Sdarrenr printf("Loading new filter rule\n"); 527145510Sdarrenr } 528145510Sdarrenr 529145510Sdarrenr obj.ipfo_ptr = is; 530145510Sdarrenr if (!(opts & OPT_DONOTHING)) 531145510Sdarrenr if (ioctl(fd, SIOCSTPUT, &obj)) { 532145510Sdarrenr perror("SIOCSTPUT"); 533161357Sguido goto freeipshead; 534145510Sdarrenr } 535145510Sdarrenr 536145510Sdarrenr if (is->ips_is.is_flags & SI_NEWFR) { 537145510Sdarrenr if (opts & OPT_VERBOSE) 538145510Sdarrenr printf("Real rule addr %p\n", is->ips_rule); 539145510Sdarrenr for (is1 = is->ips_next; is1; is1 = is1->ips_next) 540145510Sdarrenr if (is1->ips_rule == (frentry_t *)&is->ips_rule) 541145510Sdarrenr is1->ips_rule = is->ips_rule; 542145510Sdarrenr } 543161357Sguido 544161357Sguido ipshead = is->ips_next; 545161357Sguido free(is); 546145510Sdarrenr } 547145510Sdarrenr 548145510Sdarrenr return 0; 549161357Sguido 550161357Sguidofreeipshead: 551161357Sguido while ((is = ipshead) != NULL) { 552161357Sguido ipshead = is->ips_next; 553161357Sguido free(is); 554161357Sguido } 555161357Sguido if (sfd != -1) 556161357Sguido close(sfd); 557161357Sguido return 1; 558145510Sdarrenr} 559145510Sdarrenr 560145510Sdarrenr 561145510Sdarrenrint readnat(fd, file) 562255332Scy int fd; 563255332Scy char *file; 564145510Sdarrenr{ 565145510Sdarrenr nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL; 566145510Sdarrenr ipfobj_t obj; 567145510Sdarrenr int nfd, i; 568145510Sdarrenr nat_t *nat; 569145510Sdarrenr char *s; 570145510Sdarrenr int n; 571145510Sdarrenr 572145510Sdarrenr nfd = -1; 573145510Sdarrenr in = NULL; 574145510Sdarrenr ipnhead = NULL; 575145510Sdarrenr ipntail = NULL; 576145510Sdarrenr 577145510Sdarrenr if (!file) 578145510Sdarrenr file = IPF_NATFILE; 579145510Sdarrenr 580145510Sdarrenr nfd = open(file, O_RDONLY); 581145510Sdarrenr if (nfd == -1) { 582145510Sdarrenr fprintf(stderr, "%s ", file); 583145510Sdarrenr perror("nat:open"); 584145510Sdarrenr return 1; 585145510Sdarrenr } 586145510Sdarrenr 587145510Sdarrenr bzero((char *)&ipn, sizeof(ipn)); 588145510Sdarrenr 589145510Sdarrenr /* 590145510Sdarrenr * 1. Read all state information in. 591145510Sdarrenr */ 592145510Sdarrenr do { 593145510Sdarrenr i = read(nfd, &ipn, sizeof(ipn)); 594145510Sdarrenr if (i == -1) { 595145510Sdarrenr perror("read"); 596161357Sguido goto freenathead; 597145510Sdarrenr } 598145510Sdarrenr if (i == 0) 599145510Sdarrenr break; 600145510Sdarrenr if (i != sizeof(ipn)) { 601145510Sdarrenr fprintf(stderr, "nat:incomplete read: %d != %d\n", 602145510Sdarrenr i, (int)sizeof(ipn)); 603161357Sguido goto freenathead; 604145510Sdarrenr } 605145510Sdarrenr 606145510Sdarrenr in = (nat_save_t *)malloc(ipn.ipn_dsize); 607161357Sguido if (in == NULL) { 608161357Sguido fprintf(stderr, "nat:cannot malloc nat save atruct\n"); 609161357Sguido goto freenathead; 610161357Sguido } 611145510Sdarrenr 612145510Sdarrenr if (ipn.ipn_dsize > sizeof(ipn)) { 613145510Sdarrenr n = ipn.ipn_dsize - sizeof(ipn); 614145510Sdarrenr if (n > 0) { 615145510Sdarrenr s = in->ipn_data + sizeof(in->ipn_data); 616145510Sdarrenr i = read(nfd, s, n); 617145510Sdarrenr if (i == 0) 618145510Sdarrenr break; 619145510Sdarrenr if (i != n) { 620145510Sdarrenr fprintf(stderr, 621145510Sdarrenr "nat:incomplete read: %d != %d\n", 622145510Sdarrenr i, n); 623161357Sguido goto freenathead; 624145510Sdarrenr } 625145510Sdarrenr } 626145510Sdarrenr } 627145510Sdarrenr bcopy((char *)&ipn, (char *)in, sizeof(ipn)); 628145510Sdarrenr 629145510Sdarrenr /* 630145510Sdarrenr * Check to see if this is the first NAT entry that will 631145510Sdarrenr * reference a particular rule and if so, flag it as such 632145510Sdarrenr * else just adjust the rule pointer to become a pointer to 633145510Sdarrenr * the other. We do this so we have a means later for tracking 634145510Sdarrenr * who is referencing us when we get back the real pointer 635145510Sdarrenr * in is_rule after doing the ioctl. 636145510Sdarrenr */ 637145510Sdarrenr nat = &in->ipn_nat; 638145510Sdarrenr if (nat->nat_fr != NULL) { 639145510Sdarrenr for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next) 640145510Sdarrenr if (in1->ipn_rule == nat->nat_fr) 641145510Sdarrenr break; 642145510Sdarrenr if (in1 == NULL) 643145510Sdarrenr nat->nat_flags |= SI_NEWFR; 644145510Sdarrenr else 645145510Sdarrenr nat->nat_fr = &in1->ipn_fr; 646145510Sdarrenr } 647145510Sdarrenr 648145510Sdarrenr /* 649145510Sdarrenr * Use a tail-queue type list (add things to the end).. 650145510Sdarrenr */ 651145510Sdarrenr in->ipn_next = NULL; 652145510Sdarrenr if (!ipnhead) 653145510Sdarrenr ipnhead = in; 654145510Sdarrenr if (ipntail) 655145510Sdarrenr ipntail->ipn_next = in; 656145510Sdarrenr ipntail = in; 657145510Sdarrenr } while (1); 658145510Sdarrenr 659145510Sdarrenr close(nfd); 660145510Sdarrenr nfd = -1; 661145510Sdarrenr 662145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 663145510Sdarrenr obj.ipfo_type = IPFOBJ_NATSAVE; 664145510Sdarrenr 665161357Sguido while ((in = ipnhead) != NULL) { 666145510Sdarrenr if (opts & OPT_VERBOSE) 667145510Sdarrenr printf("Loading new NAT table entry\n"); 668145510Sdarrenr nat = &in->ipn_nat; 669145510Sdarrenr if (nat->nat_flags & SI_NEWFR) { 670145510Sdarrenr if (opts & OPT_VERBOSE) 671145510Sdarrenr printf("Loading new filter rule\n"); 672145510Sdarrenr } 673145510Sdarrenr 674145510Sdarrenr obj.ipfo_ptr = in; 675145510Sdarrenr obj.ipfo_size = in->ipn_dsize; 676145510Sdarrenr if (!(opts & OPT_DONOTHING)) 677145510Sdarrenr if (ioctl(fd, SIOCSTPUT, &obj)) { 678145510Sdarrenr fprintf(stderr, "in=%p:", in); 679145510Sdarrenr perror("SIOCSTPUT"); 680145510Sdarrenr return 1; 681145510Sdarrenr } 682145510Sdarrenr 683145510Sdarrenr if (nat->nat_flags & SI_NEWFR) { 684145510Sdarrenr if (opts & OPT_VERBOSE) 685145510Sdarrenr printf("Real rule addr %p\n", nat->nat_fr); 686145510Sdarrenr for (in1 = in->ipn_next; in1; in1 = in1->ipn_next) 687145510Sdarrenr if (in1->ipn_rule == &in->ipn_fr) 688145510Sdarrenr in1->ipn_rule = nat->nat_fr; 689145510Sdarrenr } 690161357Sguido 691161357Sguido ipnhead = in->ipn_next; 692161357Sguido free(in); 693145510Sdarrenr } 694145510Sdarrenr 695145510Sdarrenr return 0; 696161357Sguido 697161357Sguidofreenathead: 698161357Sguido while ((in = ipnhead) != NULL) { 699161357Sguido ipnhead = in->ipn_next; 700161357Sguido free(in); 701161357Sguido } 702161357Sguido if (nfd != -1) 703161357Sguido close(nfd); 704161357Sguido return 1; 705145510Sdarrenr} 706145510Sdarrenr 707145510Sdarrenr 708145510Sdarrenrint writenat(fd, file) 709255332Scy int fd; 710255332Scy char *file; 711145510Sdarrenr{ 712145510Sdarrenr nat_save_t *ipnp = NULL, *next = NULL; 713145510Sdarrenr ipfobj_t obj; 714145510Sdarrenr int nfd = -1; 715145510Sdarrenr natget_t ng; 716145510Sdarrenr 717145510Sdarrenr if (!file) 718145510Sdarrenr file = IPF_NATFILE; 719145510Sdarrenr 720145510Sdarrenr nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); 721145510Sdarrenr if (nfd == -1) { 722145510Sdarrenr fprintf(stderr, "%s ", file); 723145510Sdarrenr perror("nat:open"); 724145510Sdarrenr return 1; 725145510Sdarrenr } 726145510Sdarrenr 727145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 728145510Sdarrenr obj.ipfo_type = IPFOBJ_NATSAVE; 729145510Sdarrenr 730145510Sdarrenr do { 731145510Sdarrenr if (opts & OPT_VERBOSE) 732145510Sdarrenr printf("Getting nat from addr %p\n", ipnp); 733145510Sdarrenr ng.ng_ptr = next; 734145510Sdarrenr ng.ng_sz = 0; 735145510Sdarrenr if (ioctl(fd, SIOCSTGSZ, &ng)) { 736145510Sdarrenr perror("nat:SIOCSTGSZ"); 737145510Sdarrenr close(nfd); 738145510Sdarrenr if (ipnp != NULL) 739145510Sdarrenr free(ipnp); 740145510Sdarrenr return 1; 741145510Sdarrenr } 742145510Sdarrenr 743145510Sdarrenr if (opts & OPT_VERBOSE) 744145510Sdarrenr printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr); 745145510Sdarrenr 746145510Sdarrenr if (ng.ng_sz == 0) 747145510Sdarrenr break; 748145510Sdarrenr 749145510Sdarrenr if (!ipnp) 750145510Sdarrenr ipnp = malloc(ng.ng_sz); 751145510Sdarrenr else 752145510Sdarrenr ipnp = realloc((char *)ipnp, ng.ng_sz); 753145510Sdarrenr if (!ipnp) { 754145510Sdarrenr fprintf(stderr, 755145510Sdarrenr "malloc for %d bytes failed\n", ng.ng_sz); 756145510Sdarrenr break; 757145510Sdarrenr } 758145510Sdarrenr 759145510Sdarrenr bzero((char *)ipnp, ng.ng_sz); 760145510Sdarrenr obj.ipfo_size = ng.ng_sz; 761145510Sdarrenr obj.ipfo_ptr = ipnp; 762145510Sdarrenr ipnp->ipn_dsize = ng.ng_sz; 763145510Sdarrenr ipnp->ipn_next = next; 764145510Sdarrenr if (ioctl(fd, SIOCSTGET, &obj)) { 765145510Sdarrenr if (errno == ENOENT) 766145510Sdarrenr break; 767145510Sdarrenr perror("nat:SIOCSTGET"); 768145510Sdarrenr close(nfd); 769145510Sdarrenr free(ipnp); 770145510Sdarrenr return 1; 771145510Sdarrenr } 772145510Sdarrenr 773145510Sdarrenr if (opts & OPT_VERBOSE) 774145510Sdarrenr printf("Got nat next %p ipn_dsize %d ng_sz %d\n", 775145510Sdarrenr ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz); 776145510Sdarrenr if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) { 777145510Sdarrenr perror("nat:write"); 778145510Sdarrenr close(nfd); 779145510Sdarrenr free(ipnp); 780145510Sdarrenr return 1; 781145510Sdarrenr } 782145510Sdarrenr next = ipnp->ipn_next; 783145510Sdarrenr } while (ipnp && next); 784145510Sdarrenr if (ipnp != NULL) 785145510Sdarrenr free(ipnp); 786145510Sdarrenr close(nfd); 787145510Sdarrenr 788145510Sdarrenr return 0; 789145510Sdarrenr} 790145510Sdarrenr 791145510Sdarrenr 792145510Sdarrenrint writeall(dirname) 793255332Scy char *dirname; 794145510Sdarrenr{ 795145510Sdarrenr int fd, devfd; 796145510Sdarrenr 797145510Sdarrenr if (!dirname) 798145510Sdarrenr dirname = IPF_SAVEDIR; 799145510Sdarrenr 800145510Sdarrenr if (chdir(dirname)) { 801145510Sdarrenr fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname); 802145510Sdarrenr perror("chdir(IPF_SAVEDIR)"); 803145510Sdarrenr return 1; 804145510Sdarrenr } 805145510Sdarrenr 806145510Sdarrenr fd = opendevice(NULL); 807145510Sdarrenr if (fd == -1) 808145510Sdarrenr return 1; 809145510Sdarrenr if (setlock(fd, 1)) { 810145510Sdarrenr close(fd); 811145510Sdarrenr return 1; 812145510Sdarrenr } 813145510Sdarrenr 814145510Sdarrenr devfd = opendevice(IPSTATE_NAME); 815145510Sdarrenr if (devfd == -1) 816145510Sdarrenr goto bad; 817145510Sdarrenr if (writestate(devfd, NULL)) 818145510Sdarrenr goto bad; 819145510Sdarrenr close(devfd); 820145510Sdarrenr 821145510Sdarrenr devfd = opendevice(IPNAT_NAME); 822145510Sdarrenr if (devfd == -1) 823145510Sdarrenr goto bad; 824145510Sdarrenr if (writenat(devfd, NULL)) 825145510Sdarrenr goto bad; 826145510Sdarrenr close(devfd); 827145510Sdarrenr 828145510Sdarrenr if (setlock(fd, 0)) { 829145510Sdarrenr close(fd); 830145510Sdarrenr return 1; 831145510Sdarrenr } 832145510Sdarrenr 833145510Sdarrenr close(fd); 834145510Sdarrenr return 0; 835145510Sdarrenr 836145510Sdarrenrbad: 837145510Sdarrenr setlock(fd, 0); 838145510Sdarrenr close(fd); 839145510Sdarrenr return 1; 840145510Sdarrenr} 841145510Sdarrenr 842145510Sdarrenr 843145510Sdarrenrint readall(dirname) 844255332Scy char *dirname; 845145510Sdarrenr{ 846145510Sdarrenr int fd, devfd; 847145510Sdarrenr 848145510Sdarrenr if (!dirname) 849145510Sdarrenr dirname = IPF_SAVEDIR; 850145510Sdarrenr 851145510Sdarrenr if (chdir(dirname)) { 852145510Sdarrenr perror("chdir(IPF_SAVEDIR)"); 853145510Sdarrenr return 1; 854145510Sdarrenr } 855145510Sdarrenr 856145510Sdarrenr fd = opendevice(NULL); 857145510Sdarrenr if (fd == -1) 858145510Sdarrenr return 1; 859145510Sdarrenr if (setlock(fd, 1)) { 860145510Sdarrenr close(fd); 861145510Sdarrenr return 1; 862145510Sdarrenr } 863145510Sdarrenr 864145510Sdarrenr devfd = opendevice(IPSTATE_NAME); 865145510Sdarrenr if (devfd == -1) 866145510Sdarrenr return 1; 867145510Sdarrenr if (readstate(devfd, NULL)) 868145510Sdarrenr return 1; 869145510Sdarrenr close(devfd); 870145510Sdarrenr 871145510Sdarrenr devfd = opendevice(IPNAT_NAME); 872145510Sdarrenr if (devfd == -1) 873145510Sdarrenr return 1; 874145510Sdarrenr if (readnat(devfd, NULL)) 875145510Sdarrenr return 1; 876145510Sdarrenr close(devfd); 877145510Sdarrenr 878145510Sdarrenr if (setlock(fd, 0)) { 879145510Sdarrenr close(fd); 880145510Sdarrenr return 1; 881145510Sdarrenr } 882145510Sdarrenr 883145510Sdarrenr return 0; 884145510Sdarrenr} 885