ipfs.c revision 170268
1145519Sdarrenr/* $FreeBSD: head/contrib/ipfilter/tools/ipfs.c 170268 2007-06-04 02:54:36Z darrenr $ */ 2145510Sdarrenr 3145510Sdarrenr/* 4170268Sdarrenr * Copyright (C) 2001-2006 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 } 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) 166145510Sdarrenrchar *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 } 201170268Sdarrenr if (!strncmp(nat->nat_ifnames[2], ifs, olen + 1)) { 202170268Sdarrenr strcpy(nat->nat_ifnames[2], s); 203170268Sdarrenr rw = 1; 204170268Sdarrenr } 205170268Sdarrenr if (!strncmp(nat->nat_ifnames[3], ifs, olen + 1)) { 206170268Sdarrenr strcpy(nat->nat_ifnames[3], s); 207170268Sdarrenr rw = 1; 208170268Sdarrenr } 209145510Sdarrenr if (rw == 1) { 210145510Sdarrenr if (lseek(fd, pos, SEEK_SET) != pos) { 211145510Sdarrenr perror("lseek"); 212145510Sdarrenr exit(1); 213145510Sdarrenr } 214145510Sdarrenr if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) { 215145510Sdarrenr perror("write"); 216145510Sdarrenr exit(1); 217145510Sdarrenr } 218145510Sdarrenr } 219145510Sdarrenr pos = lseek(fd, 0, SEEK_CUR); 220145510Sdarrenr } 221145510Sdarrenr close(fd); 222145510Sdarrenr 223145510Sdarrenr return 0; 224145510Sdarrenr} 225145510Sdarrenr 226145510Sdarrenr 227145510Sdarrenrint main(argc,argv) 228145510Sdarrenrint argc; 229145510Sdarrenrchar *argv[]; 230145510Sdarrenr{ 231145510Sdarrenr int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0; 232145510Sdarrenr char *dirname = NULL, *filename = NULL, *ifs = NULL; 233145510Sdarrenr 234145510Sdarrenr progname = argv[0]; 235170268Sdarrenr while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1) 236145510Sdarrenr switch (c) 237145510Sdarrenr { 238145510Sdarrenr case 'd' : 239145510Sdarrenr if ((set == 0) && !dirname && !filename) 240145510Sdarrenr dirname = optarg; 241145510Sdarrenr else 242145510Sdarrenr usage(); 243145510Sdarrenr break; 244145510Sdarrenr case 'f' : 245145510Sdarrenr if ((set != 0) && !dirname && !filename) 246145510Sdarrenr filename = optarg; 247145510Sdarrenr else 248145510Sdarrenr usage(); 249145510Sdarrenr break; 250145510Sdarrenr case 'i' : 251145510Sdarrenr ifs = optarg; 252145510Sdarrenr set = 1; 253145510Sdarrenr break; 254145510Sdarrenr case 'l' : 255145510Sdarrenr if (filename || dirname || set) 256145510Sdarrenr usage(); 257145510Sdarrenr lock = 1; 258145510Sdarrenr set = 1; 259145510Sdarrenr break; 260145510Sdarrenr case 'n' : 261145510Sdarrenr opts |= OPT_DONOTHING; 262145510Sdarrenr break; 263145510Sdarrenr case 'N' : 264145510Sdarrenr if ((ns >= 0) || dirname || (rw != -1) || set) 265145510Sdarrenr usage(); 266145510Sdarrenr ns = 0; 267145510Sdarrenr set = 1; 268145510Sdarrenr break; 269145510Sdarrenr case 'r' : 270145510Sdarrenr if (dirname || (rw != -1) || (ns == -1)) 271145510Sdarrenr usage(); 272145510Sdarrenr rw = 0; 273145510Sdarrenr set = 1; 274145510Sdarrenr break; 275145510Sdarrenr case 'R' : 276145510Sdarrenr rw = 2; 277145510Sdarrenr set = 1; 278145510Sdarrenr break; 279145510Sdarrenr case 'S' : 280145510Sdarrenr if ((ns >= 0) || dirname || (rw != -1) || set) 281145510Sdarrenr usage(); 282145510Sdarrenr ns = 1; 283145510Sdarrenr set = 1; 284145510Sdarrenr break; 285145510Sdarrenr case 'u' : 286145510Sdarrenr if (filename || dirname || set) 287145510Sdarrenr usage(); 288145510Sdarrenr lock = 0; 289145510Sdarrenr set = 1; 290145510Sdarrenr break; 291145510Sdarrenr case 'v' : 292145510Sdarrenr opts |= OPT_VERBOSE; 293145510Sdarrenr break; 294145510Sdarrenr case 'w' : 295145510Sdarrenr if (dirname || (rw != -1) || (ns == -1)) 296145510Sdarrenr usage(); 297145510Sdarrenr rw = 1; 298145510Sdarrenr set = 1; 299145510Sdarrenr break; 300145510Sdarrenr case 'W' : 301145510Sdarrenr rw = 3; 302145510Sdarrenr set = 1; 303145510Sdarrenr break; 304145510Sdarrenr case '?' : 305145510Sdarrenr default : 306145510Sdarrenr usage(); 307145510Sdarrenr } 308145510Sdarrenr 309145510Sdarrenr if (ifs) { 310145510Sdarrenr if (!filename || ns < 0) 311145510Sdarrenr usage(); 312145510Sdarrenr if (ns == 0) 313145510Sdarrenr return changenatif(ifs, filename); 314145510Sdarrenr else 315145510Sdarrenr return changestateif(ifs, filename); 316145510Sdarrenr } 317145510Sdarrenr 318145510Sdarrenr if ((ns >= 0) || (lock >= 0)) { 319145510Sdarrenr if (lock >= 0) 320145510Sdarrenr devfd = opendevice(NULL); 321145510Sdarrenr else if (ns >= 0) { 322145510Sdarrenr if (ns == 1) 323145510Sdarrenr devfd = opendevice(IPSTATE_NAME); 324145510Sdarrenr else if (ns == 0) 325145510Sdarrenr devfd = opendevice(IPNAT_NAME); 326145510Sdarrenr } 327145510Sdarrenr if (devfd == -1) 328145510Sdarrenr exit(1); 329145510Sdarrenr } 330145510Sdarrenr 331145510Sdarrenr if (lock >= 0) 332145510Sdarrenr err = setlock(devfd, lock); 333145510Sdarrenr else if (rw >= 0) { 334145510Sdarrenr if (rw & 1) { /* WRITE */ 335145510Sdarrenr if (rw & 2) 336145510Sdarrenr err = writeall(dirname); 337145510Sdarrenr else { 338145510Sdarrenr if (ns == 0) 339145510Sdarrenr err = writenat(devfd, filename); 340145510Sdarrenr else if (ns == 1) 341145510Sdarrenr err = writestate(devfd, filename); 342145510Sdarrenr } 343145510Sdarrenr } else { 344145510Sdarrenr if (rw & 2) 345145510Sdarrenr err = readall(dirname); 346145510Sdarrenr else { 347145510Sdarrenr if (ns == 0) 348145510Sdarrenr err = readnat(devfd, filename); 349145510Sdarrenr else if (ns == 1) 350145510Sdarrenr err = readstate(devfd, filename); 351145510Sdarrenr } 352145510Sdarrenr } 353145510Sdarrenr } 354145510Sdarrenr return err; 355145510Sdarrenr} 356145510Sdarrenr 357145510Sdarrenr 358145510Sdarrenrint opendevice(ipfdev) 359145510Sdarrenrchar *ipfdev; 360145510Sdarrenr{ 361145510Sdarrenr int fd = -1; 362145510Sdarrenr 363145510Sdarrenr if (opts & OPT_DONOTHING) 364145510Sdarrenr return -2; 365145510Sdarrenr 366145510Sdarrenr if (!ipfdev) 367145510Sdarrenr ipfdev = IPL_NAME; 368145510Sdarrenr 369145510Sdarrenr if ((fd = open(ipfdev, O_RDWR)) == -1) 370145510Sdarrenr if ((fd = open(ipfdev, O_RDONLY)) == -1) 371145510Sdarrenr perror("open device"); 372145510Sdarrenr return fd; 373145510Sdarrenr} 374145510Sdarrenr 375145510Sdarrenr 376145510Sdarrenrvoid closedevice(fd) 377145510Sdarrenrint fd; 378145510Sdarrenr{ 379145510Sdarrenr close(fd); 380145510Sdarrenr} 381145510Sdarrenr 382145510Sdarrenr 383145510Sdarrenrint setlock(fd, lock) 384145510Sdarrenrint fd, lock; 385145510Sdarrenr{ 386145510Sdarrenr if (opts & OPT_VERBOSE) 387145510Sdarrenr printf("Turn lock %s\n", lock ? "on" : "off"); 388145510Sdarrenr if (!(opts & OPT_DONOTHING)) { 389145510Sdarrenr if (ioctl(fd, SIOCSTLCK, &lock) == -1) { 390145510Sdarrenr perror("SIOCSTLCK"); 391145510Sdarrenr return 1; 392145510Sdarrenr } 393145510Sdarrenr if (opts & OPT_VERBOSE) 394145510Sdarrenr printf("Lock now %s\n", lock ? "on" : "off"); 395145510Sdarrenr } 396145510Sdarrenr return 0; 397145510Sdarrenr} 398145510Sdarrenr 399145510Sdarrenr 400145510Sdarrenrint writestate(fd, file) 401145510Sdarrenrint fd; 402145510Sdarrenrchar *file; 403145510Sdarrenr{ 404145510Sdarrenr ipstate_save_t ips, *ipsp; 405145510Sdarrenr ipfobj_t obj; 406145510Sdarrenr int wfd = -1; 407145510Sdarrenr 408145510Sdarrenr if (!file) 409145510Sdarrenr file = IPF_STATEFILE; 410145510Sdarrenr 411145510Sdarrenr wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); 412145510Sdarrenr if (wfd == -1) { 413145510Sdarrenr fprintf(stderr, "%s ", file); 414145510Sdarrenr perror("state:open"); 415145510Sdarrenr return 1; 416145510Sdarrenr } 417145510Sdarrenr 418145510Sdarrenr ipsp = &ips; 419145510Sdarrenr bzero((char *)&obj, sizeof(obj)); 420145510Sdarrenr bzero((char *)ipsp, sizeof(ips)); 421145510Sdarrenr 422145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 423145510Sdarrenr obj.ipfo_size = sizeof(*ipsp); 424145510Sdarrenr obj.ipfo_type = IPFOBJ_STATESAVE; 425145510Sdarrenr obj.ipfo_ptr = ipsp; 426145510Sdarrenr 427145510Sdarrenr do { 428145510Sdarrenr 429145510Sdarrenr if (opts & OPT_VERBOSE) 430145510Sdarrenr printf("Getting state from addr %p\n", ips.ips_next); 431145510Sdarrenr if (ioctl(fd, SIOCSTGET, &obj)) { 432145510Sdarrenr if (errno == ENOENT) 433145510Sdarrenr break; 434145510Sdarrenr perror("state:SIOCSTGET"); 435145510Sdarrenr close(wfd); 436145510Sdarrenr return 1; 437145510Sdarrenr } 438145510Sdarrenr if (opts & OPT_VERBOSE) 439145510Sdarrenr printf("Got state next %p\n", ips.ips_next); 440145510Sdarrenr if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) { 441145510Sdarrenr perror("state:write"); 442145510Sdarrenr close(wfd); 443145510Sdarrenr return 1; 444145510Sdarrenr } 445145510Sdarrenr } while (ips.ips_next != NULL); 446145510Sdarrenr close(wfd); 447145510Sdarrenr 448145510Sdarrenr return 0; 449145510Sdarrenr} 450145510Sdarrenr 451145510Sdarrenr 452145510Sdarrenrint readstate(fd, file) 453145510Sdarrenrint fd; 454145510Sdarrenrchar *file; 455145510Sdarrenr{ 456145510Sdarrenr ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL; 457145510Sdarrenr int sfd = -1, i; 458145510Sdarrenr ipfobj_t obj; 459145510Sdarrenr 460145510Sdarrenr if (!file) 461145510Sdarrenr file = IPF_STATEFILE; 462145510Sdarrenr 463145510Sdarrenr sfd = open(file, O_RDONLY, 0600); 464145510Sdarrenr if (sfd == -1) { 465145510Sdarrenr fprintf(stderr, "%s ", file); 466145510Sdarrenr perror("open"); 467145510Sdarrenr return 1; 468145510Sdarrenr } 469145510Sdarrenr 470145510Sdarrenr bzero((char *)&ips, sizeof(ips)); 471145510Sdarrenr 472145510Sdarrenr /* 473145510Sdarrenr * 1. Read all state information in. 474145510Sdarrenr */ 475145510Sdarrenr do { 476145510Sdarrenr i = read(sfd, &ips, sizeof(ips)); 477145510Sdarrenr if (i == -1) { 478145510Sdarrenr perror("read"); 479161357Sguido goto freeipshead; 480145510Sdarrenr } 481145510Sdarrenr if (i == 0) 482145510Sdarrenr break; 483145510Sdarrenr if (i != sizeof(ips)) { 484145510Sdarrenr fprintf(stderr, "state:incomplete read: %d != %d\n", 485145510Sdarrenr i, (int)sizeof(ips)); 486161357Sguido goto freeipshead; 487145510Sdarrenr } 488145510Sdarrenr is = (ipstate_save_t *)malloc(sizeof(*is)); 489161357Sguido if (is == NULL) { 490145510Sdarrenr fprintf(stderr, "malloc failed\n"); 491161357Sguido goto freeipshead; 492145510Sdarrenr } 493145510Sdarrenr 494145510Sdarrenr bcopy((char *)&ips, (char *)is, sizeof(ips)); 495145510Sdarrenr 496145510Sdarrenr /* 497145510Sdarrenr * Check to see if this is the first state entry that will 498145510Sdarrenr * reference a particular rule and if so, flag it as such 499145510Sdarrenr * else just adjust the rule pointer to become a pointer to 500145510Sdarrenr * the other. We do this so we have a means later for tracking 501145510Sdarrenr * who is referencing us when we get back the real pointer 502145510Sdarrenr * in is_rule after doing the ioctl. 503145510Sdarrenr */ 504145510Sdarrenr for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next) 505145510Sdarrenr if (is1->ips_rule == is->ips_rule) 506145510Sdarrenr break; 507145510Sdarrenr if (is1 == NULL) 508145510Sdarrenr is->ips_is.is_flags |= SI_NEWFR; 509145510Sdarrenr else 510145510Sdarrenr is->ips_rule = (void *)&is1->ips_rule; 511145510Sdarrenr 512145510Sdarrenr /* 513145510Sdarrenr * Use a tail-queue type list (add things to the end).. 514145510Sdarrenr */ 515145510Sdarrenr is->ips_next = NULL; 516145510Sdarrenr if (!ipshead) 517145510Sdarrenr ipshead = is; 518145510Sdarrenr if (ipstail) 519145510Sdarrenr ipstail->ips_next = is; 520145510Sdarrenr ipstail = is; 521145510Sdarrenr } while (1); 522145510Sdarrenr 523145510Sdarrenr close(sfd); 524145510Sdarrenr 525145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 526145510Sdarrenr obj.ipfo_size = sizeof(*is); 527145510Sdarrenr obj.ipfo_type = IPFOBJ_STATESAVE; 528145510Sdarrenr 529161357Sguido while ((is = ipshead) != NULL) { 530145510Sdarrenr if (opts & OPT_VERBOSE) 531145510Sdarrenr printf("Loading new state table entry\n"); 532145510Sdarrenr if (is->ips_is.is_flags & SI_NEWFR) { 533145510Sdarrenr if (opts & OPT_VERBOSE) 534145510Sdarrenr printf("Loading new filter rule\n"); 535145510Sdarrenr } 536145510Sdarrenr 537145510Sdarrenr obj.ipfo_ptr = is; 538145510Sdarrenr if (!(opts & OPT_DONOTHING)) 539145510Sdarrenr if (ioctl(fd, SIOCSTPUT, &obj)) { 540145510Sdarrenr perror("SIOCSTPUT"); 541161357Sguido goto freeipshead; 542145510Sdarrenr } 543145510Sdarrenr 544145510Sdarrenr if (is->ips_is.is_flags & SI_NEWFR) { 545145510Sdarrenr if (opts & OPT_VERBOSE) 546145510Sdarrenr printf("Real rule addr %p\n", is->ips_rule); 547145510Sdarrenr for (is1 = is->ips_next; is1; is1 = is1->ips_next) 548145510Sdarrenr if (is1->ips_rule == (frentry_t *)&is->ips_rule) 549145510Sdarrenr is1->ips_rule = is->ips_rule; 550145510Sdarrenr } 551161357Sguido 552161357Sguido ipshead = is->ips_next; 553161357Sguido free(is); 554145510Sdarrenr } 555145510Sdarrenr 556145510Sdarrenr return 0; 557161357Sguido 558161357Sguidofreeipshead: 559161357Sguido while ((is = ipshead) != NULL) { 560161357Sguido ipshead = is->ips_next; 561161357Sguido free(is); 562161357Sguido } 563161357Sguido if (sfd != -1) 564161357Sguido close(sfd); 565161357Sguido return 1; 566145510Sdarrenr} 567145510Sdarrenr 568145510Sdarrenr 569145510Sdarrenrint readnat(fd, file) 570145510Sdarrenrint fd; 571145510Sdarrenrchar *file; 572145510Sdarrenr{ 573145510Sdarrenr nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL; 574145510Sdarrenr ipfobj_t obj; 575145510Sdarrenr int nfd, i; 576145510Sdarrenr nat_t *nat; 577145510Sdarrenr char *s; 578145510Sdarrenr int n; 579145510Sdarrenr 580145510Sdarrenr nfd = -1; 581145510Sdarrenr in = NULL; 582145510Sdarrenr ipnhead = NULL; 583145510Sdarrenr ipntail = NULL; 584145510Sdarrenr 585145510Sdarrenr if (!file) 586145510Sdarrenr file = IPF_NATFILE; 587145510Sdarrenr 588145510Sdarrenr nfd = open(file, O_RDONLY); 589145510Sdarrenr if (nfd == -1) { 590145510Sdarrenr fprintf(stderr, "%s ", file); 591145510Sdarrenr perror("nat:open"); 592145510Sdarrenr return 1; 593145510Sdarrenr } 594145510Sdarrenr 595145510Sdarrenr bzero((char *)&ipn, sizeof(ipn)); 596145510Sdarrenr 597145510Sdarrenr /* 598145510Sdarrenr * 1. Read all state information in. 599145510Sdarrenr */ 600145510Sdarrenr do { 601145510Sdarrenr i = read(nfd, &ipn, sizeof(ipn)); 602145510Sdarrenr if (i == -1) { 603145510Sdarrenr perror("read"); 604161357Sguido goto freenathead; 605145510Sdarrenr } 606145510Sdarrenr if (i == 0) 607145510Sdarrenr break; 608145510Sdarrenr if (i != sizeof(ipn)) { 609145510Sdarrenr fprintf(stderr, "nat:incomplete read: %d != %d\n", 610145510Sdarrenr i, (int)sizeof(ipn)); 611161357Sguido goto freenathead; 612145510Sdarrenr } 613145510Sdarrenr 614145510Sdarrenr in = (nat_save_t *)malloc(ipn.ipn_dsize); 615161357Sguido if (in == NULL) { 616161357Sguido fprintf(stderr, "nat:cannot malloc nat save atruct\n"); 617161357Sguido goto freenathead; 618161357Sguido } 619145510Sdarrenr 620145510Sdarrenr if (ipn.ipn_dsize > sizeof(ipn)) { 621145510Sdarrenr n = ipn.ipn_dsize - sizeof(ipn); 622145510Sdarrenr if (n > 0) { 623145510Sdarrenr s = in->ipn_data + sizeof(in->ipn_data); 624145510Sdarrenr i = read(nfd, s, n); 625145510Sdarrenr if (i == 0) 626145510Sdarrenr break; 627145510Sdarrenr if (i != n) { 628145510Sdarrenr fprintf(stderr, 629145510Sdarrenr "nat:incomplete read: %d != %d\n", 630145510Sdarrenr i, n); 631161357Sguido goto freenathead; 632145510Sdarrenr } 633145510Sdarrenr } 634145510Sdarrenr } 635145510Sdarrenr bcopy((char *)&ipn, (char *)in, sizeof(ipn)); 636145510Sdarrenr 637145510Sdarrenr /* 638145510Sdarrenr * Check to see if this is the first NAT entry that will 639145510Sdarrenr * reference a particular rule and if so, flag it as such 640145510Sdarrenr * else just adjust the rule pointer to become a pointer to 641145510Sdarrenr * the other. We do this so we have a means later for tracking 642145510Sdarrenr * who is referencing us when we get back the real pointer 643145510Sdarrenr * in is_rule after doing the ioctl. 644145510Sdarrenr */ 645145510Sdarrenr nat = &in->ipn_nat; 646145510Sdarrenr if (nat->nat_fr != NULL) { 647145510Sdarrenr for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next) 648145510Sdarrenr if (in1->ipn_rule == nat->nat_fr) 649145510Sdarrenr break; 650145510Sdarrenr if (in1 == NULL) 651145510Sdarrenr nat->nat_flags |= SI_NEWFR; 652145510Sdarrenr else 653145510Sdarrenr nat->nat_fr = &in1->ipn_fr; 654145510Sdarrenr } 655145510Sdarrenr 656145510Sdarrenr /* 657145510Sdarrenr * Use a tail-queue type list (add things to the end).. 658145510Sdarrenr */ 659145510Sdarrenr in->ipn_next = NULL; 660145510Sdarrenr if (!ipnhead) 661145510Sdarrenr ipnhead = in; 662145510Sdarrenr if (ipntail) 663145510Sdarrenr ipntail->ipn_next = in; 664145510Sdarrenr ipntail = in; 665145510Sdarrenr } while (1); 666145510Sdarrenr 667145510Sdarrenr close(nfd); 668145510Sdarrenr nfd = -1; 669145510Sdarrenr 670145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 671145510Sdarrenr obj.ipfo_type = IPFOBJ_NATSAVE; 672145510Sdarrenr 673161357Sguido while ((in = ipnhead) != NULL) { 674145510Sdarrenr if (opts & OPT_VERBOSE) 675145510Sdarrenr printf("Loading new NAT table entry\n"); 676145510Sdarrenr nat = &in->ipn_nat; 677145510Sdarrenr if (nat->nat_flags & SI_NEWFR) { 678145510Sdarrenr if (opts & OPT_VERBOSE) 679145510Sdarrenr printf("Loading new filter rule\n"); 680145510Sdarrenr } 681145510Sdarrenr 682145510Sdarrenr obj.ipfo_ptr = in; 683145510Sdarrenr obj.ipfo_size = in->ipn_dsize; 684145510Sdarrenr if (!(opts & OPT_DONOTHING)) 685145510Sdarrenr if (ioctl(fd, SIOCSTPUT, &obj)) { 686145510Sdarrenr fprintf(stderr, "in=%p:", in); 687145510Sdarrenr perror("SIOCSTPUT"); 688145510Sdarrenr return 1; 689145510Sdarrenr } 690145510Sdarrenr 691145510Sdarrenr if (nat->nat_flags & SI_NEWFR) { 692145510Sdarrenr if (opts & OPT_VERBOSE) 693145510Sdarrenr printf("Real rule addr %p\n", nat->nat_fr); 694145510Sdarrenr for (in1 = in->ipn_next; in1; in1 = in1->ipn_next) 695145510Sdarrenr if (in1->ipn_rule == &in->ipn_fr) 696145510Sdarrenr in1->ipn_rule = nat->nat_fr; 697145510Sdarrenr } 698161357Sguido 699161357Sguido ipnhead = in->ipn_next; 700161357Sguido free(in); 701145510Sdarrenr } 702145510Sdarrenr 703145510Sdarrenr return 0; 704161357Sguido 705161357Sguidofreenathead: 706161357Sguido while ((in = ipnhead) != NULL) { 707161357Sguido ipnhead = in->ipn_next; 708161357Sguido free(in); 709161357Sguido } 710161357Sguido if (nfd != -1) 711161357Sguido close(nfd); 712161357Sguido return 1; 713145510Sdarrenr} 714145510Sdarrenr 715145510Sdarrenr 716145510Sdarrenrint writenat(fd, file) 717145510Sdarrenrint fd; 718145510Sdarrenrchar *file; 719145510Sdarrenr{ 720145510Sdarrenr nat_save_t *ipnp = NULL, *next = NULL; 721145510Sdarrenr ipfobj_t obj; 722145510Sdarrenr int nfd = -1; 723145510Sdarrenr natget_t ng; 724145510Sdarrenr 725145510Sdarrenr if (!file) 726145510Sdarrenr file = IPF_NATFILE; 727145510Sdarrenr 728145510Sdarrenr nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); 729145510Sdarrenr if (nfd == -1) { 730145510Sdarrenr fprintf(stderr, "%s ", file); 731145510Sdarrenr perror("nat:open"); 732145510Sdarrenr return 1; 733145510Sdarrenr } 734145510Sdarrenr 735145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 736145510Sdarrenr obj.ipfo_type = IPFOBJ_NATSAVE; 737145510Sdarrenr 738145510Sdarrenr do { 739145510Sdarrenr if (opts & OPT_VERBOSE) 740145510Sdarrenr printf("Getting nat from addr %p\n", ipnp); 741145510Sdarrenr ng.ng_ptr = next; 742145510Sdarrenr ng.ng_sz = 0; 743145510Sdarrenr if (ioctl(fd, SIOCSTGSZ, &ng)) { 744145510Sdarrenr perror("nat:SIOCSTGSZ"); 745145510Sdarrenr close(nfd); 746145510Sdarrenr if (ipnp != NULL) 747145510Sdarrenr free(ipnp); 748145510Sdarrenr return 1; 749145510Sdarrenr } 750145510Sdarrenr 751145510Sdarrenr if (opts & OPT_VERBOSE) 752145510Sdarrenr printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr); 753145510Sdarrenr 754145510Sdarrenr if (ng.ng_sz == 0) 755145510Sdarrenr break; 756145510Sdarrenr 757145510Sdarrenr if (!ipnp) 758145510Sdarrenr ipnp = malloc(ng.ng_sz); 759145510Sdarrenr else 760145510Sdarrenr ipnp = realloc((char *)ipnp, ng.ng_sz); 761145510Sdarrenr if (!ipnp) { 762145510Sdarrenr fprintf(stderr, 763145510Sdarrenr "malloc for %d bytes failed\n", ng.ng_sz); 764145510Sdarrenr break; 765145510Sdarrenr } 766145510Sdarrenr 767145510Sdarrenr bzero((char *)ipnp, ng.ng_sz); 768145510Sdarrenr obj.ipfo_size = ng.ng_sz; 769145510Sdarrenr obj.ipfo_ptr = ipnp; 770145510Sdarrenr ipnp->ipn_dsize = ng.ng_sz; 771145510Sdarrenr ipnp->ipn_next = next; 772145510Sdarrenr if (ioctl(fd, SIOCSTGET, &obj)) { 773145510Sdarrenr if (errno == ENOENT) 774145510Sdarrenr break; 775145510Sdarrenr perror("nat:SIOCSTGET"); 776145510Sdarrenr close(nfd); 777145510Sdarrenr free(ipnp); 778145510Sdarrenr return 1; 779145510Sdarrenr } 780145510Sdarrenr 781145510Sdarrenr if (opts & OPT_VERBOSE) 782145510Sdarrenr printf("Got nat next %p ipn_dsize %d ng_sz %d\n", 783145510Sdarrenr ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz); 784145510Sdarrenr if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) { 785145510Sdarrenr perror("nat:write"); 786145510Sdarrenr close(nfd); 787145510Sdarrenr free(ipnp); 788145510Sdarrenr return 1; 789145510Sdarrenr } 790145510Sdarrenr next = ipnp->ipn_next; 791145510Sdarrenr } while (ipnp && next); 792145510Sdarrenr if (ipnp != NULL) 793145510Sdarrenr free(ipnp); 794145510Sdarrenr close(nfd); 795145510Sdarrenr 796145510Sdarrenr return 0; 797145510Sdarrenr} 798145510Sdarrenr 799145510Sdarrenr 800145510Sdarrenrint writeall(dirname) 801145510Sdarrenrchar *dirname; 802145510Sdarrenr{ 803145510Sdarrenr int fd, devfd; 804145510Sdarrenr 805145510Sdarrenr if (!dirname) 806145510Sdarrenr dirname = IPF_SAVEDIR; 807145510Sdarrenr 808145510Sdarrenr if (chdir(dirname)) { 809145510Sdarrenr fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname); 810145510Sdarrenr perror("chdir(IPF_SAVEDIR)"); 811145510Sdarrenr return 1; 812145510Sdarrenr } 813145510Sdarrenr 814145510Sdarrenr fd = opendevice(NULL); 815145510Sdarrenr if (fd == -1) 816145510Sdarrenr return 1; 817145510Sdarrenr if (setlock(fd, 1)) { 818145510Sdarrenr close(fd); 819145510Sdarrenr return 1; 820145510Sdarrenr } 821145510Sdarrenr 822145510Sdarrenr devfd = opendevice(IPSTATE_NAME); 823145510Sdarrenr if (devfd == -1) 824145510Sdarrenr goto bad; 825145510Sdarrenr if (writestate(devfd, NULL)) 826145510Sdarrenr goto bad; 827145510Sdarrenr close(devfd); 828145510Sdarrenr 829145510Sdarrenr devfd = opendevice(IPNAT_NAME); 830145510Sdarrenr if (devfd == -1) 831145510Sdarrenr goto bad; 832145510Sdarrenr if (writenat(devfd, NULL)) 833145510Sdarrenr goto bad; 834145510Sdarrenr close(devfd); 835145510Sdarrenr 836145510Sdarrenr if (setlock(fd, 0)) { 837145510Sdarrenr close(fd); 838145510Sdarrenr return 1; 839145510Sdarrenr } 840145510Sdarrenr 841145510Sdarrenr close(fd); 842145510Sdarrenr return 0; 843145510Sdarrenr 844145510Sdarrenrbad: 845145510Sdarrenr setlock(fd, 0); 846145510Sdarrenr close(fd); 847145510Sdarrenr return 1; 848145510Sdarrenr} 849145510Sdarrenr 850145510Sdarrenr 851145510Sdarrenrint readall(dirname) 852145510Sdarrenrchar *dirname; 853145510Sdarrenr{ 854145510Sdarrenr int fd, devfd; 855145510Sdarrenr 856145510Sdarrenr if (!dirname) 857145510Sdarrenr dirname = IPF_SAVEDIR; 858145510Sdarrenr 859145510Sdarrenr if (chdir(dirname)) { 860145510Sdarrenr perror("chdir(IPF_SAVEDIR)"); 861145510Sdarrenr return 1; 862145510Sdarrenr } 863145510Sdarrenr 864145510Sdarrenr fd = opendevice(NULL); 865145510Sdarrenr if (fd == -1) 866145510Sdarrenr return 1; 867145510Sdarrenr if (setlock(fd, 1)) { 868145510Sdarrenr close(fd); 869145510Sdarrenr return 1; 870145510Sdarrenr } 871145510Sdarrenr 872145510Sdarrenr devfd = opendevice(IPSTATE_NAME); 873145510Sdarrenr if (devfd == -1) 874145510Sdarrenr return 1; 875145510Sdarrenr if (readstate(devfd, NULL)) 876145510Sdarrenr return 1; 877145510Sdarrenr close(devfd); 878145510Sdarrenr 879145510Sdarrenr devfd = opendevice(IPNAT_NAME); 880145510Sdarrenr if (devfd == -1) 881145510Sdarrenr return 1; 882145510Sdarrenr if (readnat(devfd, NULL)) 883145510Sdarrenr return 1; 884145510Sdarrenr close(devfd); 885145510Sdarrenr 886145510Sdarrenr if (setlock(fd, 0)) { 887145510Sdarrenr close(fd); 888145510Sdarrenr return 1; 889145510Sdarrenr } 890145510Sdarrenr 891145510Sdarrenr return 0; 892145510Sdarrenr} 893