ipfs.c revision 1.3 1 1.3 mrg /* $NetBSD: ipfs.c,v 1.3 2018/02/04 08:19:42 mrg Exp $ */
2 1.1 christos
3 1.1 christos /*
4 1.2 darrenr * Copyright (C) 2012 by Darren Reed.
5 1.1 christos *
6 1.1 christos * See the IPFILTER.LICENCE file for details on licencing.
7 1.1 christos */
8 1.1 christos #ifdef __FreeBSD__
9 1.1 christos # ifndef __FreeBSD_cc_version
10 1.1 christos # include <osreldate.h>
11 1.1 christos # else
12 1.1 christos # if __FreeBSD_cc_version < 430000
13 1.1 christos # include <osreldate.h>
14 1.1 christos # endif
15 1.1 christos # endif
16 1.1 christos #endif
17 1.1 christos #include <stdio.h>
18 1.1 christos #include <unistd.h>
19 1.1 christos #include <string.h>
20 1.1 christos #include <fcntl.h>
21 1.1 christos #include <errno.h>
22 1.1 christos #if !defined(__SVR4) && !defined(__GNUC__)
23 1.1 christos #include <strings.h>
24 1.1 christos #endif
25 1.1 christos #include <sys/types.h>
26 1.1 christos #include <sys/param.h>
27 1.1 christos #include <sys/file.h>
28 1.1 christos #include <stdlib.h>
29 1.1 christos #include <stddef.h>
30 1.1 christos #include <sys/socket.h>
31 1.1 christos #include <sys/ioctl.h>
32 1.1 christos #include <netinet/in.h>
33 1.1 christos #include <netinet/in_systm.h>
34 1.1 christos #include <sys/time.h>
35 1.1 christos #include <net/if.h>
36 1.1 christos #if __FreeBSD_version >= 300000
37 1.1 christos # include <net/if_var.h>
38 1.1 christos #endif
39 1.1 christos #include <netinet/ip.h>
40 1.1 christos #include <netdb.h>
41 1.1 christos #include <arpa/nameser.h>
42 1.1 christos #include <resolv.h>
43 1.1 christos #include "ipf.h"
44 1.1 christos #include "netinet/ipl.h"
45 1.1 christos
46 1.1 christos #if !defined(lint)
47 1.3 mrg static __attribute__((__used__)) const char rcsid[] = "@(#)Id: ipfs.c,v 1.1.1.2 2012/07/22 13:44:53 darrenr Exp $";
48 1.1 christos #endif
49 1.1 christos
50 1.1 christos #ifndef IPF_SAVEDIR
51 1.1 christos # define IPF_SAVEDIR "/var/db/ipf"
52 1.1 christos #endif
53 1.1 christos #ifndef IPF_NATFILE
54 1.1 christos # define IPF_NATFILE "ipnat.ipf"
55 1.1 christos #endif
56 1.1 christos #ifndef IPF_STATEFILE
57 1.1 christos # define IPF_STATEFILE "ipstate.ipf"
58 1.1 christos #endif
59 1.1 christos
60 1.1 christos #if !defined(__SVR4) && defined(__GNUC__)
61 1.1 christos extern char *index __P((const char *, int));
62 1.1 christos #endif
63 1.1 christos
64 1.1 christos extern char *optarg;
65 1.1 christos extern int optind;
66 1.1 christos
67 1.1 christos int main __P((int, char *[]));
68 1.1 christos void usage __P((void));
69 1.1 christos int changestateif __P((char *, char *));
70 1.1 christos int changenatif __P((char *, char *));
71 1.1 christos int readstate __P((int, char *));
72 1.1 christos int readnat __P((int, char *));
73 1.1 christos int writestate __P((int, char *));
74 1.1 christos int opendevice __P((char *));
75 1.1 christos void closedevice __P((int));
76 1.1 christos int setlock __P((int, int));
77 1.1 christos int writeall __P((char *));
78 1.1 christos int readall __P((char *));
79 1.1 christos int writenat __P((int, char *));
80 1.1 christos
81 1.1 christos int opts = 0;
82 1.1 christos char *progname;
83 1.1 christos
84 1.1 christos
85 1.1 christos void usage()
86 1.1 christos {
87 1.1 christos fprintf(stderr, "usage: %s [-nv] -l\n", progname);
88 1.1 christos fprintf(stderr, "usage: %s [-nv] -u\n", progname);
89 1.1 christos fprintf(stderr, "usage: %s [-nv] [-d <dir>] -R\n", progname);
90 1.1 christos fprintf(stderr, "usage: %s [-nv] [-d <dir>] -W\n", progname);
91 1.1 christos fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -r\n", progname);
92 1.1 christos fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -w\n", progname);
93 1.1 christos fprintf(stderr, "usage: %s [-nNSv] -f <filename> -i <if1>,<if2>\n",
94 1.1 christos progname);
95 1.1 christos exit(1);
96 1.1 christos }
97 1.1 christos
98 1.1 christos
99 1.1 christos /*
100 1.1 christos * Change interface names in state information saved out to disk.
101 1.1 christos */
102 1.1 christos int changestateif(ifs, fname)
103 1.1 christos char *ifs, *fname;
104 1.1 christos {
105 1.1 christos int fd, olen, nlen, rw;
106 1.1 christos ipstate_save_t ips;
107 1.1 christos off_t pos;
108 1.1 christos char *s;
109 1.1 christos
110 1.1 christos s = strchr(ifs, ',');
111 1.1 christos if (!s)
112 1.1 christos usage();
113 1.1 christos *s++ = '\0';
114 1.1 christos nlen = strlen(s);
115 1.1 christos olen = strlen(ifs);
116 1.1 christos if (nlen >= sizeof(ips.ips_is.is_ifname) ||
117 1.1 christos olen >= sizeof(ips.ips_is.is_ifname))
118 1.1 christos usage();
119 1.1 christos
120 1.1 christos fd = open(fname, O_RDWR);
121 1.1 christos if (fd == -1) {
122 1.1 christos perror("open");
123 1.1 christos exit(1);
124 1.1 christos }
125 1.1 christos
126 1.1 christos for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) {
127 1.1 christos rw = 0;
128 1.1 christos if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) {
129 1.1 christos strcpy(ips.ips_is.is_ifname[0], s);
130 1.1 christos rw = 1;
131 1.1 christos }
132 1.1 christos if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) {
133 1.1 christos strcpy(ips.ips_is.is_ifname[1], s);
134 1.1 christos rw = 1;
135 1.1 christos }
136 1.1 christos if (!strncmp(ips.ips_is.is_ifname[2], ifs, olen + 1)) {
137 1.1 christos strcpy(ips.ips_is.is_ifname[2], s);
138 1.1 christos rw = 1;
139 1.1 christos }
140 1.1 christos if (!strncmp(ips.ips_is.is_ifname[3], ifs, olen + 1)) {
141 1.1 christos strcpy(ips.ips_is.is_ifname[3], s);
142 1.1 christos rw = 1;
143 1.1 christos }
144 1.1 christos if (rw == 1) {
145 1.1 christos if (lseek(fd, pos, SEEK_SET) != pos) {
146 1.1 christos perror("lseek");
147 1.1 christos exit(1);
148 1.1 christos }
149 1.1 christos if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) {
150 1.1 christos perror("write");
151 1.1 christos exit(1);
152 1.1 christos }
153 1.1 christos }
154 1.1 christos pos = lseek(fd, 0, SEEK_CUR);
155 1.1 christos }
156 1.1 christos close(fd);
157 1.1 christos
158 1.1 christos return 0;
159 1.1 christos }
160 1.1 christos
161 1.1 christos
162 1.1 christos /*
163 1.1 christos * Change interface names in NAT information saved out to disk.
164 1.1 christos */
165 1.1 christos int changenatif(ifs, fname)
166 1.1 christos char *ifs, *fname;
167 1.1 christos {
168 1.1 christos int fd, olen, nlen, rw;
169 1.1 christos nat_save_t ipn;
170 1.1 christos nat_t *nat;
171 1.1 christos off_t pos;
172 1.1 christos char *s;
173 1.1 christos
174 1.1 christos s = strchr(ifs, ',');
175 1.1 christos if (!s)
176 1.1 christos usage();
177 1.1 christos *s++ = '\0';
178 1.1 christos nlen = strlen(s);
179 1.1 christos olen = strlen(ifs);
180 1.1 christos nat = &ipn.ipn_nat;
181 1.1 christos if (nlen >= sizeof(nat->nat_ifnames[0]) ||
182 1.1 christos olen >= sizeof(nat->nat_ifnames[0]))
183 1.1 christos usage();
184 1.1 christos
185 1.1 christos fd = open(fname, O_RDWR);
186 1.1 christos if (fd == -1) {
187 1.1 christos perror("open");
188 1.1 christos exit(1);
189 1.1 christos }
190 1.1 christos
191 1.1 christos for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) {
192 1.1 christos rw = 0;
193 1.1 christos if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) {
194 1.1 christos strcpy(nat->nat_ifnames[0], s);
195 1.1 christos rw = 1;
196 1.1 christos }
197 1.1 christos if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) {
198 1.1 christos strcpy(nat->nat_ifnames[1], s);
199 1.1 christos rw = 1;
200 1.1 christos }
201 1.1 christos if (rw == 1) {
202 1.1 christos if (lseek(fd, pos, SEEK_SET) != pos) {
203 1.1 christos perror("lseek");
204 1.1 christos exit(1);
205 1.1 christos }
206 1.1 christos if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) {
207 1.1 christos perror("write");
208 1.1 christos exit(1);
209 1.1 christos }
210 1.1 christos }
211 1.1 christos pos = lseek(fd, 0, SEEK_CUR);
212 1.1 christos }
213 1.1 christos close(fd);
214 1.1 christos
215 1.1 christos return 0;
216 1.1 christos }
217 1.1 christos
218 1.1 christos
219 1.1 christos int main(argc,argv)
220 1.1 christos int argc;
221 1.1 christos char *argv[];
222 1.1 christos {
223 1.1 christos int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0;
224 1.1 christos char *dirname = NULL, *filename = NULL, *ifs = NULL;
225 1.1 christos
226 1.1 christos progname = argv[0];
227 1.1 christos while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1)
228 1.1 christos switch (c)
229 1.1 christos {
230 1.1 christos case 'd' :
231 1.1 christos if ((set == 0) && !dirname && !filename)
232 1.1 christos dirname = optarg;
233 1.1 christos else
234 1.1 christos usage();
235 1.1 christos break;
236 1.1 christos case 'f' :
237 1.1 christos if ((set != 0) && !dirname && !filename)
238 1.1 christos filename = optarg;
239 1.1 christos else
240 1.1 christos usage();
241 1.1 christos break;
242 1.1 christos case 'i' :
243 1.1 christos ifs = optarg;
244 1.1 christos set = 1;
245 1.1 christos break;
246 1.1 christos case 'l' :
247 1.1 christos if (filename || dirname || set)
248 1.1 christos usage();
249 1.1 christos lock = 1;
250 1.1 christos set = 1;
251 1.1 christos break;
252 1.1 christos case 'n' :
253 1.1 christos opts |= OPT_DONOTHING;
254 1.1 christos break;
255 1.1 christos case 'N' :
256 1.1 christos if ((ns >= 0) || dirname || (rw != -1) || set)
257 1.1 christos usage();
258 1.1 christos ns = 0;
259 1.1 christos set = 1;
260 1.1 christos break;
261 1.1 christos case 'r' :
262 1.1 christos if (dirname || (rw != -1) || (ns == -1))
263 1.1 christos usage();
264 1.1 christos rw = 0;
265 1.1 christos set = 1;
266 1.1 christos break;
267 1.1 christos case 'R' :
268 1.1 christos rw = 2;
269 1.1 christos set = 1;
270 1.1 christos break;
271 1.1 christos case 'S' :
272 1.1 christos if ((ns >= 0) || dirname || (rw != -1) || set)
273 1.1 christos usage();
274 1.1 christos ns = 1;
275 1.1 christos set = 1;
276 1.1 christos break;
277 1.1 christos case 'u' :
278 1.1 christos if (filename || dirname || set)
279 1.1 christos usage();
280 1.1 christos lock = 0;
281 1.1 christos set = 1;
282 1.1 christos break;
283 1.1 christos case 'v' :
284 1.1 christos opts |= OPT_VERBOSE;
285 1.1 christos break;
286 1.1 christos case 'w' :
287 1.1 christos if (dirname || (rw != -1) || (ns == -1))
288 1.1 christos usage();
289 1.1 christos rw = 1;
290 1.1 christos set = 1;
291 1.1 christos break;
292 1.1 christos case 'W' :
293 1.1 christos rw = 3;
294 1.1 christos set = 1;
295 1.1 christos break;
296 1.1 christos case '?' :
297 1.1 christos default :
298 1.1 christos usage();
299 1.1 christos }
300 1.1 christos
301 1.1 christos if (ifs) {
302 1.1 christos if (!filename || ns < 0)
303 1.1 christos usage();
304 1.1 christos if (ns == 0)
305 1.1 christos return changenatif(ifs, filename);
306 1.1 christos else
307 1.1 christos return changestateif(ifs, filename);
308 1.1 christos }
309 1.1 christos
310 1.1 christos if ((ns >= 0) || (lock >= 0)) {
311 1.1 christos if (lock >= 0)
312 1.1 christos devfd = opendevice(NULL);
313 1.1 christos else if (ns >= 0) {
314 1.1 christos if (ns == 1)
315 1.1 christos devfd = opendevice(IPSTATE_NAME);
316 1.1 christos else if (ns == 0)
317 1.1 christos devfd = opendevice(IPNAT_NAME);
318 1.1 christos }
319 1.1 christos if (devfd == -1)
320 1.1 christos exit(1);
321 1.1 christos }
322 1.1 christos
323 1.1 christos if (lock >= 0)
324 1.1 christos err = setlock(devfd, lock);
325 1.1 christos else if (rw >= 0) {
326 1.1 christos if (rw & 1) { /* WRITE */
327 1.1 christos if (rw & 2)
328 1.1 christos err = writeall(dirname);
329 1.1 christos else {
330 1.1 christos if (ns == 0)
331 1.1 christos err = writenat(devfd, filename);
332 1.1 christos else if (ns == 1)
333 1.1 christos err = writestate(devfd, filename);
334 1.1 christos }
335 1.1 christos } else {
336 1.1 christos if (rw & 2)
337 1.1 christos err = readall(dirname);
338 1.1 christos else {
339 1.1 christos if (ns == 0)
340 1.1 christos err = readnat(devfd, filename);
341 1.1 christos else if (ns == 1)
342 1.1 christos err = readstate(devfd, filename);
343 1.1 christos }
344 1.1 christos }
345 1.1 christos }
346 1.1 christos return err;
347 1.1 christos }
348 1.1 christos
349 1.1 christos
350 1.1 christos int opendevice(ipfdev)
351 1.1 christos char *ipfdev;
352 1.1 christos {
353 1.1 christos int fd = -1;
354 1.1 christos
355 1.1 christos if (opts & OPT_DONOTHING)
356 1.1 christos return -2;
357 1.1 christos
358 1.1 christos if (!ipfdev)
359 1.1 christos ipfdev = IPL_NAME;
360 1.1 christos
361 1.1 christos if ((fd = open(ipfdev, O_RDWR)) == -1)
362 1.1 christos if ((fd = open(ipfdev, O_RDONLY)) == -1)
363 1.1 christos perror("open device");
364 1.1 christos return fd;
365 1.1 christos }
366 1.1 christos
367 1.1 christos
368 1.1 christos void closedevice(fd)
369 1.1 christos int fd;
370 1.1 christos {
371 1.1 christos close(fd);
372 1.1 christos }
373 1.1 christos
374 1.1 christos
375 1.1 christos int setlock(fd, lock)
376 1.1 christos int fd, lock;
377 1.1 christos {
378 1.1 christos if (opts & OPT_VERBOSE)
379 1.1 christos printf("Turn lock %s\n", lock ? "on" : "off");
380 1.1 christos if (!(opts & OPT_DONOTHING)) {
381 1.1 christos if (ioctl(fd, SIOCSTLCK, &lock) == -1) {
382 1.1 christos perror("SIOCSTLCK");
383 1.1 christos return 1;
384 1.1 christos }
385 1.1 christos if (opts & OPT_VERBOSE)
386 1.1 christos printf("Lock now %s\n", lock ? "on" : "off");
387 1.1 christos }
388 1.1 christos return 0;
389 1.1 christos }
390 1.1 christos
391 1.1 christos
392 1.1 christos int writestate(fd, file)
393 1.1 christos int fd;
394 1.1 christos char *file;
395 1.1 christos {
396 1.1 christos ipstate_save_t ips, *ipsp;
397 1.1 christos ipfobj_t obj;
398 1.1 christos int wfd = -1;
399 1.1 christos
400 1.1 christos if (!file)
401 1.1 christos file = IPF_STATEFILE;
402 1.1 christos
403 1.1 christos wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
404 1.1 christos if (wfd == -1) {
405 1.1 christos fprintf(stderr, "%s ", file);
406 1.1 christos perror("state:open");
407 1.1 christos return 1;
408 1.1 christos }
409 1.1 christos
410 1.1 christos ipsp = &ips;
411 1.1 christos bzero((char *)&obj, sizeof(obj));
412 1.1 christos bzero((char *)ipsp, sizeof(ips));
413 1.1 christos
414 1.1 christos obj.ipfo_rev = IPFILTER_VERSION;
415 1.1 christos obj.ipfo_size = sizeof(*ipsp);
416 1.1 christos obj.ipfo_type = IPFOBJ_STATESAVE;
417 1.1 christos obj.ipfo_ptr = ipsp;
418 1.1 christos
419 1.1 christos do {
420 1.1 christos
421 1.1 christos if (opts & OPT_VERBOSE)
422 1.1 christos printf("Getting state from addr %p\n", ips.ips_next);
423 1.1 christos if (ioctl(fd, SIOCSTGET, &obj)) {
424 1.1 christos if (errno == ENOENT)
425 1.1 christos break;
426 1.1 christos perror("state:SIOCSTGET");
427 1.1 christos close(wfd);
428 1.1 christos return 1;
429 1.1 christos }
430 1.1 christos if (opts & OPT_VERBOSE)
431 1.1 christos printf("Got state next %p\n", ips.ips_next);
432 1.1 christos if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) {
433 1.1 christos perror("state:write");
434 1.1 christos close(wfd);
435 1.1 christos return 1;
436 1.1 christos }
437 1.1 christos } while (ips.ips_next != NULL);
438 1.1 christos close(wfd);
439 1.1 christos
440 1.1 christos return 0;
441 1.1 christos }
442 1.1 christos
443 1.1 christos
444 1.1 christos int readstate(fd, file)
445 1.1 christos int fd;
446 1.1 christos char *file;
447 1.1 christos {
448 1.1 christos ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL;
449 1.1 christos int sfd = -1, i;
450 1.1 christos ipfobj_t obj;
451 1.1 christos
452 1.1 christos if (!file)
453 1.1 christos file = IPF_STATEFILE;
454 1.1 christos
455 1.1 christos sfd = open(file, O_RDONLY, 0600);
456 1.1 christos if (sfd == -1) {
457 1.1 christos fprintf(stderr, "%s ", file);
458 1.1 christos perror("open");
459 1.1 christos return 1;
460 1.1 christos }
461 1.1 christos
462 1.1 christos bzero((char *)&ips, sizeof(ips));
463 1.1 christos
464 1.1 christos /*
465 1.1 christos * 1. Read all state information in.
466 1.1 christos */
467 1.1 christos do {
468 1.1 christos i = read(sfd, &ips, sizeof(ips));
469 1.1 christos if (i == -1) {
470 1.1 christos perror("read");
471 1.1 christos goto freeipshead;
472 1.1 christos }
473 1.1 christos if (i == 0)
474 1.1 christos break;
475 1.1 christos if (i != sizeof(ips)) {
476 1.1 christos fprintf(stderr, "state:incomplete read: %d != %d\n",
477 1.1 christos i, (int)sizeof(ips));
478 1.1 christos goto freeipshead;
479 1.1 christos }
480 1.1 christos is = (ipstate_save_t *)malloc(sizeof(*is));
481 1.1 christos if (is == NULL) {
482 1.1 christos fprintf(stderr, "malloc failed\n");
483 1.1 christos goto freeipshead;
484 1.1 christos }
485 1.1 christos
486 1.1 christos bcopy((char *)&ips, (char *)is, sizeof(ips));
487 1.1 christos
488 1.1 christos /*
489 1.1 christos * Check to see if this is the first state entry that will
490 1.1 christos * reference a particular rule and if so, flag it as such
491 1.1 christos * else just adjust the rule pointer to become a pointer to
492 1.1 christos * the other. We do this so we have a means later for tracking
493 1.1 christos * who is referencing us when we get back the real pointer
494 1.1 christos * in is_rule after doing the ioctl.
495 1.1 christos */
496 1.1 christos for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next)
497 1.1 christos if (is1->ips_rule == is->ips_rule)
498 1.1 christos break;
499 1.1 christos if (is1 == NULL)
500 1.1 christos is->ips_is.is_flags |= SI_NEWFR;
501 1.1 christos else
502 1.1 christos is->ips_rule = (void *)&is1->ips_rule;
503 1.1 christos
504 1.1 christos /*
505 1.1 christos * Use a tail-queue type list (add things to the end)..
506 1.1 christos */
507 1.1 christos is->ips_next = NULL;
508 1.1 christos if (!ipshead)
509 1.1 christos ipshead = is;
510 1.1 christos if (ipstail)
511 1.1 christos ipstail->ips_next = is;
512 1.1 christos ipstail = is;
513 1.1 christos } while (1);
514 1.1 christos
515 1.1 christos close(sfd);
516 1.1 christos
517 1.1 christos obj.ipfo_rev = IPFILTER_VERSION;
518 1.1 christos obj.ipfo_size = sizeof(*is);
519 1.1 christos obj.ipfo_type = IPFOBJ_STATESAVE;
520 1.1 christos
521 1.1 christos while ((is = ipshead) != NULL) {
522 1.1 christos if (opts & OPT_VERBOSE)
523 1.1 christos printf("Loading new state table entry\n");
524 1.1 christos if (is->ips_is.is_flags & SI_NEWFR) {
525 1.1 christos if (opts & OPT_VERBOSE)
526 1.1 christos printf("Loading new filter rule\n");
527 1.1 christos }
528 1.1 christos
529 1.1 christos obj.ipfo_ptr = is;
530 1.1 christos if (!(opts & OPT_DONOTHING))
531 1.1 christos if (ioctl(fd, SIOCSTPUT, &obj)) {
532 1.1 christos perror("SIOCSTPUT");
533 1.1 christos goto freeipshead;
534 1.1 christos }
535 1.1 christos
536 1.1 christos if (is->ips_is.is_flags & SI_NEWFR) {
537 1.1 christos if (opts & OPT_VERBOSE)
538 1.1 christos printf("Real rule addr %p\n", is->ips_rule);
539 1.1 christos for (is1 = is->ips_next; is1; is1 = is1->ips_next)
540 1.1 christos if (is1->ips_rule == (frentry_t *)&is->ips_rule)
541 1.1 christos is1->ips_rule = is->ips_rule;
542 1.1 christos }
543 1.1 christos
544 1.1 christos ipshead = is->ips_next;
545 1.1 christos free(is);
546 1.1 christos }
547 1.1 christos
548 1.1 christos return 0;
549 1.1 christos
550 1.1 christos freeipshead:
551 1.1 christos while ((is = ipshead) != NULL) {
552 1.1 christos ipshead = is->ips_next;
553 1.1 christos free(is);
554 1.1 christos }
555 1.1 christos if (sfd != -1)
556 1.1 christos close(sfd);
557 1.1 christos return 1;
558 1.1 christos }
559 1.1 christos
560 1.1 christos
561 1.1 christos int readnat(fd, file)
562 1.1 christos int fd;
563 1.1 christos char *file;
564 1.1 christos {
565 1.1 christos nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL;
566 1.1 christos ipfobj_t obj;
567 1.1 christos int nfd, i;
568 1.1 christos nat_t *nat;
569 1.1 christos char *s;
570 1.1 christos int n;
571 1.1 christos
572 1.1 christos nfd = -1;
573 1.1 christos in = NULL;
574 1.1 christos ipnhead = NULL;
575 1.1 christos ipntail = NULL;
576 1.1 christos
577 1.1 christos if (!file)
578 1.1 christos file = IPF_NATFILE;
579 1.1 christos
580 1.1 christos nfd = open(file, O_RDONLY);
581 1.1 christos if (nfd == -1) {
582 1.1 christos fprintf(stderr, "%s ", file);
583 1.1 christos perror("nat:open");
584 1.1 christos return 1;
585 1.1 christos }
586 1.1 christos
587 1.1 christos bzero((char *)&ipn, sizeof(ipn));
588 1.1 christos
589 1.1 christos /*
590 1.1 christos * 1. Read all state information in.
591 1.1 christos */
592 1.1 christos do {
593 1.1 christos i = read(nfd, &ipn, sizeof(ipn));
594 1.1 christos if (i == -1) {
595 1.1 christos perror("read");
596 1.1 christos goto freenathead;
597 1.1 christos }
598 1.1 christos if (i == 0)
599 1.1 christos break;
600 1.1 christos if (i != sizeof(ipn)) {
601 1.1 christos fprintf(stderr, "nat:incomplete read: %d != %d\n",
602 1.1 christos i, (int)sizeof(ipn));
603 1.1 christos goto freenathead;
604 1.1 christos }
605 1.1 christos
606 1.1 christos in = (nat_save_t *)malloc(ipn.ipn_dsize);
607 1.1 christos if (in == NULL) {
608 1.1 christos fprintf(stderr, "nat:cannot malloc nat save atruct\n");
609 1.1 christos goto freenathead;
610 1.1 christos }
611 1.1 christos
612 1.1 christos if (ipn.ipn_dsize > sizeof(ipn)) {
613 1.1 christos n = ipn.ipn_dsize - sizeof(ipn);
614 1.1 christos if (n > 0) {
615 1.1 christos s = in->ipn_data + sizeof(in->ipn_data);
616 1.1 christos i = read(nfd, s, n);
617 1.1 christos if (i == 0)
618 1.1 christos break;
619 1.1 christos if (i != n) {
620 1.1 christos fprintf(stderr,
621 1.1 christos "nat:incomplete read: %d != %d\n",
622 1.1 christos i, n);
623 1.1 christos goto freenathead;
624 1.1 christos }
625 1.1 christos }
626 1.1 christos }
627 1.1 christos bcopy((char *)&ipn, (char *)in, sizeof(ipn));
628 1.1 christos
629 1.1 christos /*
630 1.1 christos * Check to see if this is the first NAT entry that will
631 1.1 christos * reference a particular rule and if so, flag it as such
632 1.1 christos * else just adjust the rule pointer to become a pointer to
633 1.1 christos * the other. We do this so we have a means later for tracking
634 1.1 christos * who is referencing us when we get back the real pointer
635 1.1 christos * in is_rule after doing the ioctl.
636 1.1 christos */
637 1.1 christos nat = &in->ipn_nat;
638 1.1 christos if (nat->nat_fr != NULL) {
639 1.1 christos for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next)
640 1.1 christos if (in1->ipn_rule == nat->nat_fr)
641 1.1 christos break;
642 1.1 christos if (in1 == NULL)
643 1.1 christos nat->nat_flags |= SI_NEWFR;
644 1.1 christos else
645 1.1 christos nat->nat_fr = &in1->ipn_fr;
646 1.1 christos }
647 1.1 christos
648 1.1 christos /*
649 1.1 christos * Use a tail-queue type list (add things to the end)..
650 1.1 christos */
651 1.1 christos in->ipn_next = NULL;
652 1.1 christos if (!ipnhead)
653 1.1 christos ipnhead = in;
654 1.1 christos if (ipntail)
655 1.1 christos ipntail->ipn_next = in;
656 1.1 christos ipntail = in;
657 1.1 christos } while (1);
658 1.1 christos
659 1.1 christos close(nfd);
660 1.1 christos nfd = -1;
661 1.1 christos
662 1.1 christos obj.ipfo_rev = IPFILTER_VERSION;
663 1.1 christos obj.ipfo_type = IPFOBJ_NATSAVE;
664 1.1 christos
665 1.1 christos while ((in = ipnhead) != NULL) {
666 1.1 christos if (opts & OPT_VERBOSE)
667 1.1 christos printf("Loading new NAT table entry\n");
668 1.1 christos nat = &in->ipn_nat;
669 1.1 christos if (nat->nat_flags & SI_NEWFR) {
670 1.1 christos if (opts & OPT_VERBOSE)
671 1.1 christos printf("Loading new filter rule\n");
672 1.1 christos }
673 1.1 christos
674 1.1 christos obj.ipfo_ptr = in;
675 1.1 christos obj.ipfo_size = in->ipn_dsize;
676 1.1 christos if (!(opts & OPT_DONOTHING))
677 1.1 christos if (ioctl(fd, SIOCSTPUT, &obj)) {
678 1.1 christos fprintf(stderr, "in=%p:", in);
679 1.1 christos perror("SIOCSTPUT");
680 1.1 christos return 1;
681 1.1 christos }
682 1.1 christos
683 1.1 christos if (nat->nat_flags & SI_NEWFR) {
684 1.1 christos if (opts & OPT_VERBOSE)
685 1.1 christos printf("Real rule addr %p\n", nat->nat_fr);
686 1.1 christos for (in1 = in->ipn_next; in1; in1 = in1->ipn_next)
687 1.1 christos if (in1->ipn_rule == &in->ipn_fr)
688 1.1 christos in1->ipn_rule = nat->nat_fr;
689 1.1 christos }
690 1.1 christos
691 1.1 christos ipnhead = in->ipn_next;
692 1.1 christos free(in);
693 1.1 christos }
694 1.1 christos
695 1.1 christos return 0;
696 1.1 christos
697 1.1 christos freenathead:
698 1.1 christos while ((in = ipnhead) != NULL) {
699 1.1 christos ipnhead = in->ipn_next;
700 1.1 christos free(in);
701 1.1 christos }
702 1.1 christos if (nfd != -1)
703 1.1 christos close(nfd);
704 1.1 christos return 1;
705 1.1 christos }
706 1.1 christos
707 1.1 christos
708 1.1 christos int writenat(fd, file)
709 1.1 christos int fd;
710 1.1 christos char *file;
711 1.1 christos {
712 1.1 christos nat_save_t *ipnp = NULL, *next = NULL;
713 1.1 christos ipfobj_t obj;
714 1.1 christos int nfd = -1;
715 1.1 christos natget_t ng;
716 1.1 christos
717 1.1 christos if (!file)
718 1.1 christos file = IPF_NATFILE;
719 1.1 christos
720 1.1 christos nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
721 1.1 christos if (nfd == -1) {
722 1.1 christos fprintf(stderr, "%s ", file);
723 1.1 christos perror("nat:open");
724 1.1 christos return 1;
725 1.1 christos }
726 1.1 christos
727 1.1 christos obj.ipfo_rev = IPFILTER_VERSION;
728 1.1 christos obj.ipfo_type = IPFOBJ_NATSAVE;
729 1.1 christos
730 1.1 christos do {
731 1.1 christos if (opts & OPT_VERBOSE)
732 1.1 christos printf("Getting nat from addr %p\n", ipnp);
733 1.1 christos ng.ng_ptr = next;
734 1.1 christos ng.ng_sz = 0;
735 1.1 christos if (ioctl(fd, SIOCSTGSZ, &ng)) {
736 1.1 christos perror("nat:SIOCSTGSZ");
737 1.1 christos close(nfd);
738 1.1 christos if (ipnp != NULL)
739 1.1 christos free(ipnp);
740 1.1 christos return 1;
741 1.1 christos }
742 1.1 christos
743 1.1 christos if (opts & OPT_VERBOSE)
744 1.1 christos printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr);
745 1.1 christos
746 1.1 christos if (ng.ng_sz == 0)
747 1.1 christos break;
748 1.1 christos
749 1.1 christos if (!ipnp)
750 1.1 christos ipnp = malloc(ng.ng_sz);
751 1.1 christos else
752 1.1 christos ipnp = realloc((char *)ipnp, ng.ng_sz);
753 1.1 christos if (!ipnp) {
754 1.1 christos fprintf(stderr,
755 1.1 christos "malloc for %d bytes failed\n", ng.ng_sz);
756 1.1 christos break;
757 1.1 christos }
758 1.1 christos
759 1.1 christos bzero((char *)ipnp, ng.ng_sz);
760 1.1 christos obj.ipfo_size = ng.ng_sz;
761 1.1 christos obj.ipfo_ptr = ipnp;
762 1.1 christos ipnp->ipn_dsize = ng.ng_sz;
763 1.1 christos ipnp->ipn_next = next;
764 1.1 christos if (ioctl(fd, SIOCSTGET, &obj)) {
765 1.1 christos if (errno == ENOENT)
766 1.1 christos break;
767 1.1 christos perror("nat:SIOCSTGET");
768 1.1 christos close(nfd);
769 1.1 christos free(ipnp);
770 1.1 christos return 1;
771 1.1 christos }
772 1.1 christos
773 1.1 christos if (opts & OPT_VERBOSE)
774 1.1 christos printf("Got nat next %p ipn_dsize %d ng_sz %d\n",
775 1.1 christos ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz);
776 1.1 christos if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) {
777 1.1 christos perror("nat:write");
778 1.1 christos close(nfd);
779 1.1 christos free(ipnp);
780 1.1 christos return 1;
781 1.1 christos }
782 1.1 christos next = ipnp->ipn_next;
783 1.1 christos } while (ipnp && next);
784 1.1 christos if (ipnp != NULL)
785 1.1 christos free(ipnp);
786 1.1 christos close(nfd);
787 1.1 christos
788 1.1 christos return 0;
789 1.1 christos }
790 1.1 christos
791 1.1 christos
792 1.1 christos int writeall(dirname)
793 1.1 christos char *dirname;
794 1.1 christos {
795 1.1 christos int fd, devfd;
796 1.1 christos
797 1.1 christos if (!dirname)
798 1.1 christos dirname = IPF_SAVEDIR;
799 1.1 christos
800 1.1 christos if (chdir(dirname)) {
801 1.1 christos fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname);
802 1.1 christos perror("chdir(IPF_SAVEDIR)");
803 1.1 christos return 1;
804 1.1 christos }
805 1.1 christos
806 1.1 christos fd = opendevice(NULL);
807 1.1 christos if (fd == -1)
808 1.1 christos return 1;
809 1.1 christos if (setlock(fd, 1)) {
810 1.1 christos close(fd);
811 1.1 christos return 1;
812 1.1 christos }
813 1.1 christos
814 1.1 christos devfd = opendevice(IPSTATE_NAME);
815 1.1 christos if (devfd == -1)
816 1.1 christos goto bad;
817 1.1 christos if (writestate(devfd, NULL))
818 1.1 christos goto bad;
819 1.1 christos close(devfd);
820 1.1 christos
821 1.1 christos devfd = opendevice(IPNAT_NAME);
822 1.1 christos if (devfd == -1)
823 1.1 christos goto bad;
824 1.1 christos if (writenat(devfd, NULL))
825 1.1 christos goto bad;
826 1.1 christos close(devfd);
827 1.1 christos
828 1.1 christos if (setlock(fd, 0)) {
829 1.1 christos close(fd);
830 1.1 christos return 1;
831 1.1 christos }
832 1.1 christos
833 1.1 christos close(fd);
834 1.1 christos return 0;
835 1.1 christos
836 1.1 christos bad:
837 1.1 christos setlock(fd, 0);
838 1.1 christos close(fd);
839 1.1 christos return 1;
840 1.1 christos }
841 1.1 christos
842 1.1 christos
843 1.1 christos int readall(dirname)
844 1.1 christos char *dirname;
845 1.1 christos {
846 1.1 christos int fd, devfd;
847 1.1 christos
848 1.1 christos if (!dirname)
849 1.1 christos dirname = IPF_SAVEDIR;
850 1.1 christos
851 1.1 christos if (chdir(dirname)) {
852 1.1 christos perror("chdir(IPF_SAVEDIR)");
853 1.1 christos return 1;
854 1.1 christos }
855 1.1 christos
856 1.1 christos fd = opendevice(NULL);
857 1.1 christos if (fd == -1)
858 1.1 christos return 1;
859 1.1 christos if (setlock(fd, 1)) {
860 1.1 christos close(fd);
861 1.1 christos return 1;
862 1.1 christos }
863 1.1 christos
864 1.1 christos devfd = opendevice(IPSTATE_NAME);
865 1.1 christos if (devfd == -1)
866 1.1 christos return 1;
867 1.1 christos if (readstate(devfd, NULL))
868 1.1 christos return 1;
869 1.1 christos close(devfd);
870 1.1 christos
871 1.1 christos devfd = opendevice(IPNAT_NAME);
872 1.1 christos if (devfd == -1)
873 1.1 christos return 1;
874 1.1 christos if (readnat(devfd, NULL))
875 1.1 christos return 1;
876 1.1 christos close(devfd);
877 1.1 christos
878 1.1 christos if (setlock(fd, 0)) {
879 1.1 christos close(fd);
880 1.1 christos return 1;
881 1.1 christos }
882 1.1 christos
883 1.1 christos return 0;
884 1.1 christos }
885