xref: /freebsd/sbin/ipf/ipfs/ipfs.c (revision efeb8bffe34422937c7f8df836afb5b817366d16)
141edb306SCy Schubert /*	$FreeBSD$	*/
241edb306SCy Schubert 
341edb306SCy Schubert /*
441edb306SCy Schubert  * Copyright (C) 2012 by Darren Reed.
541edb306SCy Schubert  *
641edb306SCy Schubert  * See the IPFILTER.LICENCE file for details on licencing.
741edb306SCy Schubert  */
841edb306SCy Schubert #include <stdio.h>
941edb306SCy Schubert #include <unistd.h>
1041edb306SCy Schubert #include <string.h>
1141edb306SCy Schubert #include <fcntl.h>
1241edb306SCy Schubert #include <errno.h>
1341edb306SCy Schubert #if !defined(__SVR4) && !defined(__GNUC__)
1441edb306SCy Schubert #include <strings.h>
1541edb306SCy Schubert #endif
1641edb306SCy Schubert #include <sys/types.h>
1741edb306SCy Schubert #include <sys/param.h>
1841edb306SCy Schubert #include <sys/file.h>
1941edb306SCy Schubert #include <stdlib.h>
2041edb306SCy Schubert #include <stddef.h>
2141edb306SCy Schubert #include <sys/socket.h>
2241edb306SCy Schubert #include <sys/ioctl.h>
2341edb306SCy Schubert #include <netinet/in.h>
2441edb306SCy Schubert #include <netinet/in_systm.h>
2541edb306SCy Schubert #include <sys/time.h>
2641edb306SCy Schubert #include <net/if.h>
2741edb306SCy Schubert #include <netinet/ip.h>
2841edb306SCy Schubert #include <netdb.h>
2941edb306SCy Schubert #include <arpa/nameser.h>
3041edb306SCy Schubert #include <resolv.h>
3141edb306SCy Schubert #include "ipf.h"
3241edb306SCy Schubert #include "netinet/ipl.h"
3341edb306SCy Schubert 
3441edb306SCy Schubert #if !defined(lint)
3541edb306SCy Schubert static const char rcsid[] = "@(#)$Id$";
3641edb306SCy Schubert #endif
3741edb306SCy Schubert 
3841edb306SCy Schubert #ifndef	IPF_SAVEDIR
3941edb306SCy Schubert # define	IPF_SAVEDIR	"/var/db/ipf"
4041edb306SCy Schubert #endif
4141edb306SCy Schubert #ifndef IPF_NATFILE
4241edb306SCy Schubert # define	IPF_NATFILE	"ipnat.ipf"
4341edb306SCy Schubert #endif
4441edb306SCy Schubert #ifndef IPF_STATEFILE
4541edb306SCy Schubert # define	IPF_STATEFILE	"ipstate.ipf"
4641edb306SCy Schubert #endif
4741edb306SCy Schubert 
4841edb306SCy Schubert #if !defined(__SVR4) && defined(__GNUC__)
4941edb306SCy Schubert extern	char	*index(const char *, int);
5041edb306SCy Schubert #endif
5141edb306SCy Schubert 
5241edb306SCy Schubert extern	char	*optarg;
5341edb306SCy Schubert extern	int	optind;
5441edb306SCy Schubert 
5541edb306SCy Schubert int	main(int, char *[]);
5641edb306SCy Schubert void	usage(void);
5741edb306SCy Schubert int	changestateif(char *, char *);
5841edb306SCy Schubert int	changenatif(char *, char *);
5941edb306SCy Schubert int	readstate(int, char *);
6041edb306SCy Schubert int	readnat(int, char *);
6141edb306SCy Schubert int	writestate(int, char *);
6241edb306SCy Schubert int	opendevice(char *);
6341edb306SCy Schubert void	closedevice(int);
6441edb306SCy Schubert int	setlock(int, int);
6541edb306SCy Schubert int	writeall(char *);
6641edb306SCy Schubert int	readall(char *);
6741edb306SCy Schubert int	writenat(int, char *);
6841edb306SCy Schubert 
6941edb306SCy Schubert int	opts = 0;
7041edb306SCy Schubert char	*progname;
7141edb306SCy Schubert 
7241edb306SCy Schubert 
7341edb306SCy Schubert void usage()
7441edb306SCy Schubert {
7541edb306SCy Schubert 	fprintf(stderr, "usage: %s [-nv] -l\n", progname);
7641edb306SCy Schubert 	fprintf(stderr, "usage: %s [-nv] -u\n", progname);
7741edb306SCy Schubert 	fprintf(stderr, "usage: %s [-nv] [-d <dir>] -R\n", progname);
7841edb306SCy Schubert 	fprintf(stderr, "usage: %s [-nv] [-d <dir>] -W\n", progname);
7941edb306SCy Schubert 	fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -r\n", progname);
8041edb306SCy Schubert 	fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -w\n", progname);
8141edb306SCy Schubert 	fprintf(stderr, "usage: %s [-nNSv] -f <filename> -i <if1>,<if2>\n",
8241edb306SCy Schubert 		progname);
8341edb306SCy Schubert 	exit(1);
8441edb306SCy Schubert }
8541edb306SCy Schubert 
8641edb306SCy Schubert 
8741edb306SCy Schubert /*
8841edb306SCy Schubert  * Change interface names in state information saved out to disk.
8941edb306SCy Schubert  */
90*efeb8bffSCy Schubert int changestateif(char *ifs, char *fname)
9141edb306SCy Schubert {
9241edb306SCy Schubert 	int fd, olen, nlen, rw;
9341edb306SCy Schubert 	ipstate_save_t ips;
9441edb306SCy Schubert 	off_t pos;
9541edb306SCy Schubert 	char *s;
9641edb306SCy Schubert 
9741edb306SCy Schubert 	s = strchr(ifs, ',');
9841edb306SCy Schubert 	if (!s)
9941edb306SCy Schubert 		usage();
10041edb306SCy Schubert 	*s++ = '\0';
10141edb306SCy Schubert 	nlen = strlen(s);
10241edb306SCy Schubert 	olen = strlen(ifs);
10341edb306SCy Schubert 	if (nlen >= sizeof(ips.ips_is.is_ifname) ||
10441edb306SCy Schubert 	    olen >= sizeof(ips.ips_is.is_ifname))
10541edb306SCy Schubert 		usage();
10641edb306SCy Schubert 
10741edb306SCy Schubert 	fd = open(fname, O_RDWR);
10841edb306SCy Schubert 	if (fd == -1) {
10941edb306SCy Schubert 		perror("open");
11041edb306SCy Schubert 		exit(1);
11141edb306SCy Schubert 	}
11241edb306SCy Schubert 
11341edb306SCy Schubert 	for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) {
11441edb306SCy Schubert 		rw = 0;
11541edb306SCy Schubert 		if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) {
11641edb306SCy Schubert 			strcpy(ips.ips_is.is_ifname[0], s);
11741edb306SCy Schubert 			rw = 1;
11841edb306SCy Schubert 		}
11941edb306SCy Schubert 		if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) {
12041edb306SCy Schubert 			strcpy(ips.ips_is.is_ifname[1], s);
12141edb306SCy Schubert 			rw = 1;
12241edb306SCy Schubert 		}
12341edb306SCy Schubert 		if (!strncmp(ips.ips_is.is_ifname[2], ifs, olen + 1)) {
12441edb306SCy Schubert 			strcpy(ips.ips_is.is_ifname[2], s);
12541edb306SCy Schubert 			rw = 1;
12641edb306SCy Schubert 		}
12741edb306SCy Schubert 		if (!strncmp(ips.ips_is.is_ifname[3], ifs, olen + 1)) {
12841edb306SCy Schubert 			strcpy(ips.ips_is.is_ifname[3], s);
12941edb306SCy Schubert 			rw = 1;
13041edb306SCy Schubert 		}
13141edb306SCy Schubert 		if (rw == 1) {
13241edb306SCy Schubert 			if (lseek(fd, pos, SEEK_SET) != pos) {
13341edb306SCy Schubert 				perror("lseek");
13441edb306SCy Schubert 				exit(1);
13541edb306SCy Schubert 			}
13641edb306SCy Schubert 			if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) {
13741edb306SCy Schubert 				perror("write");
13841edb306SCy Schubert 				exit(1);
13941edb306SCy Schubert 			}
14041edb306SCy Schubert 		}
14141edb306SCy Schubert 		pos = lseek(fd, 0, SEEK_CUR);
14241edb306SCy Schubert 	}
14341edb306SCy Schubert 	close(fd);
14441edb306SCy Schubert 
14541edb306SCy Schubert 	return 0;
14641edb306SCy Schubert }
14741edb306SCy Schubert 
14841edb306SCy Schubert 
14941edb306SCy Schubert /*
15041edb306SCy Schubert  * Change interface names in NAT information saved out to disk.
15141edb306SCy Schubert  */
152*efeb8bffSCy Schubert int changenatif(char *ifs, char *fname)
15341edb306SCy Schubert {
15441edb306SCy Schubert 	int fd, olen, nlen, rw;
15541edb306SCy Schubert 	nat_save_t ipn;
15641edb306SCy Schubert 	nat_t *nat;
15741edb306SCy Schubert 	off_t pos;
15841edb306SCy Schubert 	char *s;
15941edb306SCy Schubert 
16041edb306SCy Schubert 	s = strchr(ifs, ',');
16141edb306SCy Schubert 	if (!s)
16241edb306SCy Schubert 		usage();
16341edb306SCy Schubert 	*s++ = '\0';
16441edb306SCy Schubert 	nlen = strlen(s);
16541edb306SCy Schubert 	olen = strlen(ifs);
16641edb306SCy Schubert 	nat = &ipn.ipn_nat;
16741edb306SCy Schubert 	if (nlen >= sizeof(nat->nat_ifnames[0]) ||
16841edb306SCy Schubert 	    olen >= sizeof(nat->nat_ifnames[0]))
16941edb306SCy Schubert 		usage();
17041edb306SCy Schubert 
17141edb306SCy Schubert 	fd = open(fname, O_RDWR);
17241edb306SCy Schubert 	if (fd == -1) {
17341edb306SCy Schubert 		perror("open");
17441edb306SCy Schubert 		exit(1);
17541edb306SCy Schubert 	}
17641edb306SCy Schubert 
17741edb306SCy Schubert 	for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) {
17841edb306SCy Schubert 		rw = 0;
17941edb306SCy Schubert 		if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) {
18041edb306SCy Schubert 			strcpy(nat->nat_ifnames[0], s);
18141edb306SCy Schubert 			rw = 1;
18241edb306SCy Schubert 		}
18341edb306SCy Schubert 		if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) {
18441edb306SCy Schubert 			strcpy(nat->nat_ifnames[1], s);
18541edb306SCy Schubert 			rw = 1;
18641edb306SCy Schubert 		}
18741edb306SCy Schubert 		if (rw == 1) {
18841edb306SCy Schubert 			if (lseek(fd, pos, SEEK_SET) != pos) {
18941edb306SCy Schubert 				perror("lseek");
19041edb306SCy Schubert 				exit(1);
19141edb306SCy Schubert 			}
19241edb306SCy Schubert 			if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) {
19341edb306SCy Schubert 				perror("write");
19441edb306SCy Schubert 				exit(1);
19541edb306SCy Schubert 			}
19641edb306SCy Schubert 		}
19741edb306SCy Schubert 		pos = lseek(fd, 0, SEEK_CUR);
19841edb306SCy Schubert 	}
19941edb306SCy Schubert 	close(fd);
20041edb306SCy Schubert 
20141edb306SCy Schubert 	return 0;
20241edb306SCy Schubert }
20341edb306SCy Schubert 
20441edb306SCy Schubert 
205*efeb8bffSCy Schubert int main(int argc, char *argv[])
20641edb306SCy Schubert {
20741edb306SCy Schubert 	int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0;
20841edb306SCy Schubert 	char *dirname = NULL, *filename = NULL, *ifs = NULL;
20941edb306SCy Schubert 
21041edb306SCy Schubert 	progname = argv[0];
21141edb306SCy Schubert 	while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1)
21241edb306SCy Schubert 		switch (c)
21341edb306SCy Schubert 		{
21441edb306SCy Schubert 		case 'd' :
21541edb306SCy Schubert 			if ((set == 0) && !dirname && !filename)
21641edb306SCy Schubert 				dirname = optarg;
21741edb306SCy Schubert 			else
21841edb306SCy Schubert 				usage();
21941edb306SCy Schubert 			break;
22041edb306SCy Schubert 		case 'f' :
22141edb306SCy Schubert 			if ((set != 0) && !dirname && !filename)
22241edb306SCy Schubert 				filename = optarg;
22341edb306SCy Schubert 			else
22441edb306SCy Schubert 				usage();
22541edb306SCy Schubert 			break;
22641edb306SCy Schubert 		case 'i' :
22741edb306SCy Schubert 			ifs = optarg;
22841edb306SCy Schubert 			set = 1;
22941edb306SCy Schubert 			break;
23041edb306SCy Schubert 		case 'l' :
23141edb306SCy Schubert 			if (filename || dirname || set)
23241edb306SCy Schubert 				usage();
23341edb306SCy Schubert 			lock = 1;
23441edb306SCy Schubert 			set = 1;
23541edb306SCy Schubert 			break;
23641edb306SCy Schubert 		case 'n' :
23741edb306SCy Schubert 			opts |= OPT_DONOTHING;
23841edb306SCy Schubert 			break;
23941edb306SCy Schubert 		case 'N' :
24041edb306SCy Schubert 			if ((ns >= 0) || dirname || (rw != -1) || set)
24141edb306SCy Schubert 				usage();
24241edb306SCy Schubert 			ns = 0;
24341edb306SCy Schubert 			set = 1;
24441edb306SCy Schubert 			break;
24541edb306SCy Schubert 		case 'r' :
24641edb306SCy Schubert 			if (dirname || (rw != -1) || (ns == -1))
24741edb306SCy Schubert 				usage();
24841edb306SCy Schubert 			rw = 0;
24941edb306SCy Schubert 			set = 1;
25041edb306SCy Schubert 			break;
25141edb306SCy Schubert 		case 'R' :
25241edb306SCy Schubert 			rw = 2;
25341edb306SCy Schubert 			set = 1;
25441edb306SCy Schubert 			break;
25541edb306SCy Schubert 		case 'S' :
25641edb306SCy Schubert 			if ((ns >= 0) || dirname || (rw != -1) || set)
25741edb306SCy Schubert 				usage();
25841edb306SCy Schubert 			ns = 1;
25941edb306SCy Schubert 			set = 1;
26041edb306SCy Schubert 			break;
26141edb306SCy Schubert 		case 'u' :
26241edb306SCy Schubert 			if (filename || dirname || set)
26341edb306SCy Schubert 				usage();
26441edb306SCy Schubert 			lock = 0;
26541edb306SCy Schubert 			set = 1;
26641edb306SCy Schubert 			break;
26741edb306SCy Schubert 		case 'v' :
26841edb306SCy Schubert 			opts |= OPT_VERBOSE;
26941edb306SCy Schubert 			break;
27041edb306SCy Schubert 		case 'w' :
27141edb306SCy Schubert 			if (dirname || (rw != -1) || (ns == -1))
27241edb306SCy Schubert 				usage();
27341edb306SCy Schubert 			rw = 1;
27441edb306SCy Schubert 			set = 1;
27541edb306SCy Schubert 			break;
27641edb306SCy Schubert 		case 'W' :
27741edb306SCy Schubert 			rw = 3;
27841edb306SCy Schubert 			set = 1;
27941edb306SCy Schubert 			break;
28041edb306SCy Schubert 		case '?' :
28141edb306SCy Schubert 		default :
28241edb306SCy Schubert 			usage();
28341edb306SCy Schubert 		}
28441edb306SCy Schubert 
28541edb306SCy Schubert 	if (ifs) {
28641edb306SCy Schubert 		if (!filename || ns < 0)
28741edb306SCy Schubert 			usage();
28841edb306SCy Schubert 		if (ns == 0)
28941edb306SCy Schubert 			return changenatif(ifs, filename);
29041edb306SCy Schubert 		else
29141edb306SCy Schubert 			return changestateif(ifs, filename);
29241edb306SCy Schubert 	}
29341edb306SCy Schubert 
29441edb306SCy Schubert 	if ((ns >= 0) || (lock >= 0)) {
29541edb306SCy Schubert 		if (lock >= 0)
29641edb306SCy Schubert 			devfd = opendevice(NULL);
29741edb306SCy Schubert 		else if (ns >= 0) {
29841edb306SCy Schubert 			if (ns == 1)
29941edb306SCy Schubert 				devfd = opendevice(IPSTATE_NAME);
30041edb306SCy Schubert 			else if (ns == 0)
30141edb306SCy Schubert 				devfd = opendevice(IPNAT_NAME);
30241edb306SCy Schubert 		}
30341edb306SCy Schubert 		if (devfd == -1)
30441edb306SCy Schubert 			exit(1);
30541edb306SCy Schubert 	}
30641edb306SCy Schubert 
30741edb306SCy Schubert 	if (lock >= 0)
30841edb306SCy Schubert 		err = setlock(devfd, lock);
30941edb306SCy Schubert 	else if (rw >= 0) {
31041edb306SCy Schubert 		if (rw & 1) {	/* WRITE */
31141edb306SCy Schubert 			if (rw & 2)
31241edb306SCy Schubert 				err = writeall(dirname);
31341edb306SCy Schubert 			else {
31441edb306SCy Schubert 				if (ns == 0)
31541edb306SCy Schubert 					err = writenat(devfd, filename);
31641edb306SCy Schubert 				else if (ns == 1)
31741edb306SCy Schubert 					err = writestate(devfd, filename);
31841edb306SCy Schubert 			}
31941edb306SCy Schubert 		} else {
32041edb306SCy Schubert 			if (rw & 2)
32141edb306SCy Schubert 				err = readall(dirname);
32241edb306SCy Schubert 			else {
32341edb306SCy Schubert 				if (ns == 0)
32441edb306SCy Schubert 					err = readnat(devfd, filename);
32541edb306SCy Schubert 				else if (ns == 1)
32641edb306SCy Schubert 					err = readstate(devfd, filename);
32741edb306SCy Schubert 			}
32841edb306SCy Schubert 		}
32941edb306SCy Schubert 	}
33041edb306SCy Schubert 	return err;
33141edb306SCy Schubert }
33241edb306SCy Schubert 
33341edb306SCy Schubert 
334*efeb8bffSCy Schubert int opendevice(char *ipfdev)
33541edb306SCy Schubert {
33641edb306SCy Schubert 	int fd = -1;
33741edb306SCy Schubert 
33841edb306SCy Schubert 	if (opts & OPT_DONOTHING)
33941edb306SCy Schubert 		return -2;
34041edb306SCy Schubert 
34141edb306SCy Schubert 	if (!ipfdev)
34241edb306SCy Schubert 		ipfdev = IPL_NAME;
34341edb306SCy Schubert 
34441edb306SCy Schubert 	if ((fd = open(ipfdev, O_RDWR)) == -1)
34541edb306SCy Schubert 		if ((fd = open(ipfdev, O_RDONLY)) == -1)
34641edb306SCy Schubert 			perror("open device");
34741edb306SCy Schubert 	return fd;
34841edb306SCy Schubert }
34941edb306SCy Schubert 
35041edb306SCy Schubert 
351*efeb8bffSCy Schubert void closedevice(int fd)
35241edb306SCy Schubert {
35341edb306SCy Schubert 	close(fd);
35441edb306SCy Schubert }
35541edb306SCy Schubert 
35641edb306SCy Schubert 
357*efeb8bffSCy Schubert int setlock(int fd, int lock)
35841edb306SCy Schubert {
35941edb306SCy Schubert 	if (opts & OPT_VERBOSE)
36041edb306SCy Schubert 		printf("Turn lock %s\n", lock ? "on" : "off");
36141edb306SCy Schubert 	if (!(opts & OPT_DONOTHING)) {
36241edb306SCy Schubert 		if (ioctl(fd, SIOCSTLCK, &lock) == -1) {
36341edb306SCy Schubert 			perror("SIOCSTLCK");
36441edb306SCy Schubert 			return 1;
36541edb306SCy Schubert 		}
36641edb306SCy Schubert 		if (opts & OPT_VERBOSE)
36741edb306SCy Schubert 			printf("Lock now %s\n", lock ? "on" : "off");
36841edb306SCy Schubert 	}
36941edb306SCy Schubert 	return 0;
37041edb306SCy Schubert }
37141edb306SCy Schubert 
37241edb306SCy Schubert 
373*efeb8bffSCy Schubert int writestate(int fd, char *file)
37441edb306SCy Schubert {
37541edb306SCy Schubert 	ipstate_save_t ips, *ipsp;
37641edb306SCy Schubert 	ipfobj_t obj;
37741edb306SCy Schubert 	int wfd = -1;
37841edb306SCy Schubert 
37941edb306SCy Schubert 	if (!file)
38041edb306SCy Schubert 		file = IPF_STATEFILE;
38141edb306SCy Schubert 
38241edb306SCy Schubert 	wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
38341edb306SCy Schubert 	if (wfd == -1) {
38441edb306SCy Schubert 		fprintf(stderr, "%s ", file);
38541edb306SCy Schubert 		perror("state:open");
38641edb306SCy Schubert 		return 1;
38741edb306SCy Schubert 	}
38841edb306SCy Schubert 
38941edb306SCy Schubert 	ipsp = &ips;
39041edb306SCy Schubert 	bzero((char *)&obj, sizeof(obj));
39141edb306SCy Schubert 	bzero((char *)ipsp, sizeof(ips));
39241edb306SCy Schubert 
39341edb306SCy Schubert 	obj.ipfo_rev = IPFILTER_VERSION;
39441edb306SCy Schubert 	obj.ipfo_size = sizeof(*ipsp);
39541edb306SCy Schubert 	obj.ipfo_type = IPFOBJ_STATESAVE;
39641edb306SCy Schubert 	obj.ipfo_ptr = ipsp;
39741edb306SCy Schubert 
39841edb306SCy Schubert 	do {
39941edb306SCy Schubert 
40041edb306SCy Schubert 		if (opts & OPT_VERBOSE)
40141edb306SCy Schubert 			printf("Getting state from addr %p\n", ips.ips_next);
40241edb306SCy Schubert 		if (ioctl(fd, SIOCSTGET, &obj)) {
40341edb306SCy Schubert 			if (errno == ENOENT)
40441edb306SCy Schubert 				break;
40541edb306SCy Schubert 			perror("state:SIOCSTGET");
40641edb306SCy Schubert 			close(wfd);
40741edb306SCy Schubert 			return 1;
40841edb306SCy Schubert 		}
40941edb306SCy Schubert 		if (opts & OPT_VERBOSE)
41041edb306SCy Schubert 			printf("Got state next %p\n", ips.ips_next);
41141edb306SCy Schubert 		if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) {
41241edb306SCy Schubert 			perror("state:write");
41341edb306SCy Schubert 			close(wfd);
41441edb306SCy Schubert 			return 1;
41541edb306SCy Schubert 		}
41641edb306SCy Schubert 	} while (ips.ips_next != NULL);
41741edb306SCy Schubert 	close(wfd);
41841edb306SCy Schubert 
41941edb306SCy Schubert 	return 0;
42041edb306SCy Schubert }
42141edb306SCy Schubert 
42241edb306SCy Schubert 
423*efeb8bffSCy Schubert int readstate(int fd, char *file)
42441edb306SCy Schubert {
42541edb306SCy Schubert 	ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL;
42641edb306SCy Schubert 	int sfd = -1, i;
42741edb306SCy Schubert 	ipfobj_t obj;
42841edb306SCy Schubert 
42941edb306SCy Schubert 	if (!file)
43041edb306SCy Schubert 		file = IPF_STATEFILE;
43141edb306SCy Schubert 
43241edb306SCy Schubert 	sfd = open(file, O_RDONLY, 0600);
43341edb306SCy Schubert 	if (sfd == -1) {
43441edb306SCy Schubert 		fprintf(stderr, "%s ", file);
43541edb306SCy Schubert 		perror("open");
43641edb306SCy Schubert 		return 1;
43741edb306SCy Schubert 	}
43841edb306SCy Schubert 
43941edb306SCy Schubert 	bzero((char *)&ips, sizeof(ips));
44041edb306SCy Schubert 
44141edb306SCy Schubert 	/*
44241edb306SCy Schubert 	 * 1. Read all state information in.
44341edb306SCy Schubert 	 */
44441edb306SCy Schubert 	do {
44541edb306SCy Schubert 		i = read(sfd, &ips, sizeof(ips));
44641edb306SCy Schubert 		if (i == -1) {
44741edb306SCy Schubert 			perror("read");
44841edb306SCy Schubert 			goto freeipshead;
44941edb306SCy Schubert 		}
45041edb306SCy Schubert 		if (i == 0)
45141edb306SCy Schubert 			break;
45241edb306SCy Schubert 		if (i != sizeof(ips)) {
45341edb306SCy Schubert 			fprintf(stderr, "state:incomplete read: %d != %d\n",
45441edb306SCy Schubert 				i, (int)sizeof(ips));
45541edb306SCy Schubert 			goto freeipshead;
45641edb306SCy Schubert 		}
45741edb306SCy Schubert 		is = (ipstate_save_t *)malloc(sizeof(*is));
45841edb306SCy Schubert 		if (is == NULL) {
45941edb306SCy Schubert 			fprintf(stderr, "malloc failed\n");
46041edb306SCy Schubert 			goto freeipshead;
46141edb306SCy Schubert 		}
46241edb306SCy Schubert 
46341edb306SCy Schubert 		bcopy((char *)&ips, (char *)is, sizeof(ips));
46441edb306SCy Schubert 
46541edb306SCy Schubert 		/*
46641edb306SCy Schubert 		 * Check to see if this is the first state entry that will
46741edb306SCy Schubert 		 * reference a particular rule and if so, flag it as such
46841edb306SCy Schubert 		 * else just adjust the rule pointer to become a pointer to
46941edb306SCy Schubert 		 * the other.  We do this so we have a means later for tracking
47041edb306SCy Schubert 		 * who is referencing us when we get back the real pointer
47141edb306SCy Schubert 		 * in is_rule after doing the ioctl.
47241edb306SCy Schubert 		 */
47341edb306SCy Schubert 		for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next)
47441edb306SCy Schubert 			if (is1->ips_rule == is->ips_rule)
47541edb306SCy Schubert 				break;
47641edb306SCy Schubert 		if (is1 == NULL)
47741edb306SCy Schubert 			is->ips_is.is_flags |= SI_NEWFR;
47841edb306SCy Schubert 		else
47941edb306SCy Schubert 			is->ips_rule = (void *)&is1->ips_rule;
48041edb306SCy Schubert 
48141edb306SCy Schubert 		/*
48241edb306SCy Schubert 		 * Use a tail-queue type list (add things to the end)..
48341edb306SCy Schubert 		 */
48441edb306SCy Schubert 		is->ips_next = NULL;
48541edb306SCy Schubert 		if (!ipshead)
48641edb306SCy Schubert 			ipshead = is;
48741edb306SCy Schubert 		if (ipstail)
48841edb306SCy Schubert 			ipstail->ips_next = is;
48941edb306SCy Schubert 		ipstail = is;
49041edb306SCy Schubert 	} while (1);
49141edb306SCy Schubert 
49241edb306SCy Schubert 	close(sfd);
49341edb306SCy Schubert 
49441edb306SCy Schubert 	obj.ipfo_rev = IPFILTER_VERSION;
49541edb306SCy Schubert 	obj.ipfo_size = sizeof(*is);
49641edb306SCy Schubert 	obj.ipfo_type = IPFOBJ_STATESAVE;
49741edb306SCy Schubert 
49841edb306SCy Schubert 	while ((is = ipshead) != NULL) {
49941edb306SCy Schubert 		if (opts & OPT_VERBOSE)
50041edb306SCy Schubert 			printf("Loading new state table entry\n");
50141edb306SCy Schubert 		if (is->ips_is.is_flags & SI_NEWFR) {
50241edb306SCy Schubert 			if (opts & OPT_VERBOSE)
50341edb306SCy Schubert 				printf("Loading new filter rule\n");
50441edb306SCy Schubert 		}
50541edb306SCy Schubert 
50641edb306SCy Schubert 		obj.ipfo_ptr = is;
50741edb306SCy Schubert 		if (!(opts & OPT_DONOTHING))
50841edb306SCy Schubert 			if (ioctl(fd, SIOCSTPUT, &obj)) {
50941edb306SCy Schubert 				perror("SIOCSTPUT");
51041edb306SCy Schubert 				goto freeipshead;
51141edb306SCy Schubert 			}
51241edb306SCy Schubert 
51341edb306SCy Schubert 		if (is->ips_is.is_flags & SI_NEWFR) {
51441edb306SCy Schubert 			if (opts & OPT_VERBOSE)
51541edb306SCy Schubert 				printf("Real rule addr %p\n", is->ips_rule);
51641edb306SCy Schubert 			for (is1 = is->ips_next; is1; is1 = is1->ips_next)
51741edb306SCy Schubert 				if (is1->ips_rule == (frentry_t *)&is->ips_rule)
51841edb306SCy Schubert 					is1->ips_rule = is->ips_rule;
51941edb306SCy Schubert 		}
52041edb306SCy Schubert 
52141edb306SCy Schubert 		ipshead = is->ips_next;
52241edb306SCy Schubert 		free(is);
52341edb306SCy Schubert 	}
52441edb306SCy Schubert 
52541edb306SCy Schubert 	return 0;
52641edb306SCy Schubert 
52741edb306SCy Schubert freeipshead:
52841edb306SCy Schubert 	while ((is = ipshead) != NULL) {
52941edb306SCy Schubert 		ipshead = is->ips_next;
53041edb306SCy Schubert 		free(is);
53141edb306SCy Schubert 	}
53241edb306SCy Schubert 	if (sfd != -1)
53341edb306SCy Schubert 		close(sfd);
53441edb306SCy Schubert 	return 1;
53541edb306SCy Schubert }
53641edb306SCy Schubert 
53741edb306SCy Schubert 
538*efeb8bffSCy Schubert int readnat(int fd, char *file)
53941edb306SCy Schubert {
54041edb306SCy Schubert 	nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL;
54141edb306SCy Schubert 	ipfobj_t obj;
54241edb306SCy Schubert 	int nfd, i;
54341edb306SCy Schubert 	nat_t *nat;
54441edb306SCy Schubert 	char *s;
54541edb306SCy Schubert 	int n;
54641edb306SCy Schubert 
54741edb306SCy Schubert 	nfd = -1;
54841edb306SCy Schubert 	in = NULL;
54941edb306SCy Schubert 	ipnhead = NULL;
55041edb306SCy Schubert 	ipntail = NULL;
55141edb306SCy Schubert 
55241edb306SCy Schubert 	if (!file)
55341edb306SCy Schubert 		file = IPF_NATFILE;
55441edb306SCy Schubert 
55541edb306SCy Schubert 	nfd = open(file, O_RDONLY);
55641edb306SCy Schubert 	if (nfd == -1) {
55741edb306SCy Schubert 		fprintf(stderr, "%s ", file);
55841edb306SCy Schubert 		perror("nat:open");
55941edb306SCy Schubert 		return 1;
56041edb306SCy Schubert 	}
56141edb306SCy Schubert 
56241edb306SCy Schubert 	bzero((char *)&ipn, sizeof(ipn));
56341edb306SCy Schubert 
56441edb306SCy Schubert 	/*
56541edb306SCy Schubert 	 * 1. Read all state information in.
56641edb306SCy Schubert 	 */
56741edb306SCy Schubert 	do {
56841edb306SCy Schubert 		i = read(nfd, &ipn, sizeof(ipn));
56941edb306SCy Schubert 		if (i == -1) {
57041edb306SCy Schubert 			perror("read");
57141edb306SCy Schubert 			goto freenathead;
57241edb306SCy Schubert 		}
57341edb306SCy Schubert 		if (i == 0)
57441edb306SCy Schubert 			break;
57541edb306SCy Schubert 		if (i != sizeof(ipn)) {
57641edb306SCy Schubert 			fprintf(stderr, "nat:incomplete read: %d != %d\n",
57741edb306SCy Schubert 				i, (int)sizeof(ipn));
57841edb306SCy Schubert 			goto freenathead;
57941edb306SCy Schubert 		}
58041edb306SCy Schubert 
58141edb306SCy Schubert 		in = (nat_save_t *)malloc(ipn.ipn_dsize);
58241edb306SCy Schubert 		if (in == NULL) {
58341edb306SCy Schubert 			fprintf(stderr, "nat:cannot malloc nat save atruct\n");
58441edb306SCy Schubert 			goto freenathead;
58541edb306SCy Schubert 		}
58641edb306SCy Schubert 
58741edb306SCy Schubert 		if (ipn.ipn_dsize > sizeof(ipn)) {
58841edb306SCy Schubert 			n = ipn.ipn_dsize - sizeof(ipn);
58941edb306SCy Schubert 			if (n > 0) {
59041edb306SCy Schubert 				s = in->ipn_data + sizeof(in->ipn_data);
59141edb306SCy Schubert  				i = read(nfd, s, n);
59241edb306SCy Schubert 				if (i == 0)
59341edb306SCy Schubert 					break;
59441edb306SCy Schubert 				if (i != n) {
59541edb306SCy Schubert 					fprintf(stderr,
59641edb306SCy Schubert 					    "nat:incomplete read: %d != %d\n",
59741edb306SCy Schubert 					    i, n);
59841edb306SCy Schubert 					goto freenathead;
59941edb306SCy Schubert 				}
60041edb306SCy Schubert 			}
60141edb306SCy Schubert 		}
60241edb306SCy Schubert 		bcopy((char *)&ipn, (char *)in, sizeof(ipn));
60341edb306SCy Schubert 
60441edb306SCy Schubert 		/*
60541edb306SCy Schubert 		 * Check to see if this is the first NAT entry that will
60641edb306SCy Schubert 		 * reference a particular rule and if so, flag it as such
60741edb306SCy Schubert 		 * else just adjust the rule pointer to become a pointer to
60841edb306SCy Schubert 		 * the other.  We do this so we have a means later for tracking
60941edb306SCy Schubert 		 * who is referencing us when we get back the real pointer
61041edb306SCy Schubert 		 * in is_rule after doing the ioctl.
61141edb306SCy Schubert 		 */
61241edb306SCy Schubert 		nat = &in->ipn_nat;
61341edb306SCy Schubert 		if (nat->nat_fr != NULL) {
61441edb306SCy Schubert 			for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next)
61541edb306SCy Schubert 				if (in1->ipn_rule == nat->nat_fr)
61641edb306SCy Schubert 					break;
61741edb306SCy Schubert 			if (in1 == NULL)
61841edb306SCy Schubert 				nat->nat_flags |= SI_NEWFR;
61941edb306SCy Schubert 			else
62041edb306SCy Schubert 				nat->nat_fr = &in1->ipn_fr;
62141edb306SCy Schubert 		}
62241edb306SCy Schubert 
62341edb306SCy Schubert 		/*
62441edb306SCy Schubert 		 * Use a tail-queue type list (add things to the end)..
62541edb306SCy Schubert 		 */
62641edb306SCy Schubert 		in->ipn_next = NULL;
62741edb306SCy Schubert 		if (!ipnhead)
62841edb306SCy Schubert 			ipnhead = in;
62941edb306SCy Schubert 		if (ipntail)
63041edb306SCy Schubert 			ipntail->ipn_next = in;
63141edb306SCy Schubert 		ipntail = in;
63241edb306SCy Schubert 	} while (1);
63341edb306SCy Schubert 
63441edb306SCy Schubert 	close(nfd);
63541edb306SCy Schubert 	nfd = -1;
63641edb306SCy Schubert 
63741edb306SCy Schubert 	obj.ipfo_rev = IPFILTER_VERSION;
63841edb306SCy Schubert 	obj.ipfo_type = IPFOBJ_NATSAVE;
63941edb306SCy Schubert 
64041edb306SCy Schubert 	while ((in = ipnhead) != NULL) {
64141edb306SCy Schubert 		if (opts & OPT_VERBOSE)
64241edb306SCy Schubert 			printf("Loading new NAT table entry\n");
64341edb306SCy Schubert 		nat = &in->ipn_nat;
64441edb306SCy Schubert 		if (nat->nat_flags & SI_NEWFR) {
64541edb306SCy Schubert 			if (opts & OPT_VERBOSE)
64641edb306SCy Schubert 				printf("Loading new filter rule\n");
64741edb306SCy Schubert 		}
64841edb306SCy Schubert 
64941edb306SCy Schubert 		obj.ipfo_ptr = in;
65041edb306SCy Schubert 		obj.ipfo_size = in->ipn_dsize;
65141edb306SCy Schubert 		if (!(opts & OPT_DONOTHING))
65241edb306SCy Schubert 			if (ioctl(fd, SIOCSTPUT, &obj)) {
65341edb306SCy Schubert 				fprintf(stderr, "in=%p:", in);
65441edb306SCy Schubert 				perror("SIOCSTPUT");
65541edb306SCy Schubert 				return 1;
65641edb306SCy Schubert 			}
65741edb306SCy Schubert 
65841edb306SCy Schubert 		if (nat->nat_flags & SI_NEWFR) {
65941edb306SCy Schubert 			if (opts & OPT_VERBOSE)
66041edb306SCy Schubert 				printf("Real rule addr %p\n", nat->nat_fr);
66141edb306SCy Schubert 			for (in1 = in->ipn_next; in1; in1 = in1->ipn_next)
66241edb306SCy Schubert 				if (in1->ipn_rule == &in->ipn_fr)
66341edb306SCy Schubert 					in1->ipn_rule = nat->nat_fr;
66441edb306SCy Schubert 		}
66541edb306SCy Schubert 
66641edb306SCy Schubert 		ipnhead = in->ipn_next;
66741edb306SCy Schubert 		free(in);
66841edb306SCy Schubert 	}
66941edb306SCy Schubert 
67041edb306SCy Schubert 	return 0;
67141edb306SCy Schubert 
67241edb306SCy Schubert freenathead:
67341edb306SCy Schubert 	while ((in = ipnhead) != NULL) {
67441edb306SCy Schubert 		ipnhead = in->ipn_next;
67541edb306SCy Schubert 		free(in);
67641edb306SCy Schubert 	}
67741edb306SCy Schubert 	if (nfd != -1)
67841edb306SCy Schubert 		close(nfd);
67941edb306SCy Schubert 	return 1;
68041edb306SCy Schubert }
68141edb306SCy Schubert 
68241edb306SCy Schubert 
683*efeb8bffSCy Schubert int writenat(int fd, char *file)
68441edb306SCy Schubert {
68541edb306SCy Schubert 	nat_save_t *ipnp = NULL, *next = NULL;
68641edb306SCy Schubert 	ipfobj_t obj;
68741edb306SCy Schubert 	int nfd = -1;
68841edb306SCy Schubert 	natget_t ng;
68941edb306SCy Schubert 
69041edb306SCy Schubert 	if (!file)
69141edb306SCy Schubert 		file = IPF_NATFILE;
69241edb306SCy Schubert 
69341edb306SCy Schubert 	nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
69441edb306SCy Schubert 	if (nfd == -1) {
69541edb306SCy Schubert 		fprintf(stderr, "%s ", file);
69641edb306SCy Schubert 		perror("nat:open");
69741edb306SCy Schubert 		return 1;
69841edb306SCy Schubert 	}
69941edb306SCy Schubert 
70041edb306SCy Schubert 	obj.ipfo_rev = IPFILTER_VERSION;
70141edb306SCy Schubert 	obj.ipfo_type = IPFOBJ_NATSAVE;
70241edb306SCy Schubert 
70341edb306SCy Schubert 	do {
70441edb306SCy Schubert 		if (opts & OPT_VERBOSE)
70541edb306SCy Schubert 			printf("Getting nat from addr %p\n", ipnp);
70641edb306SCy Schubert 		ng.ng_ptr = next;
70741edb306SCy Schubert 		ng.ng_sz = 0;
70841edb306SCy Schubert 		if (ioctl(fd, SIOCSTGSZ, &ng)) {
70941edb306SCy Schubert 			perror("nat:SIOCSTGSZ");
71041edb306SCy Schubert 			close(nfd);
71141edb306SCy Schubert 			if (ipnp != NULL)
71241edb306SCy Schubert 				free(ipnp);
71341edb306SCy Schubert 			return 1;
71441edb306SCy Schubert 		}
71541edb306SCy Schubert 
71641edb306SCy Schubert 		if (opts & OPT_VERBOSE)
71741edb306SCy Schubert 			printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr);
71841edb306SCy Schubert 
71941edb306SCy Schubert 		if (ng.ng_sz == 0)
72041edb306SCy Schubert 			break;
72141edb306SCy Schubert 
72241edb306SCy Schubert 		if (!ipnp)
72341edb306SCy Schubert 			ipnp = malloc(ng.ng_sz);
72441edb306SCy Schubert 		else
72541edb306SCy Schubert 			ipnp = realloc((char *)ipnp, ng.ng_sz);
72641edb306SCy Schubert 		if (!ipnp) {
72741edb306SCy Schubert 			fprintf(stderr,
72841edb306SCy Schubert 				"malloc for %d bytes failed\n", ng.ng_sz);
72941edb306SCy Schubert 			break;
73041edb306SCy Schubert 		}
73141edb306SCy Schubert 
73241edb306SCy Schubert 		bzero((char *)ipnp, ng.ng_sz);
73341edb306SCy Schubert 		obj.ipfo_size = ng.ng_sz;
73441edb306SCy Schubert 		obj.ipfo_ptr = ipnp;
73541edb306SCy Schubert 		ipnp->ipn_dsize = ng.ng_sz;
73641edb306SCy Schubert 		ipnp->ipn_next = next;
73741edb306SCy Schubert 		if (ioctl(fd, SIOCSTGET, &obj)) {
73841edb306SCy Schubert 			if (errno == ENOENT)
73941edb306SCy Schubert 				break;
74041edb306SCy Schubert 			perror("nat:SIOCSTGET");
74141edb306SCy Schubert 			close(nfd);
74241edb306SCy Schubert 			free(ipnp);
74341edb306SCy Schubert 			return 1;
74441edb306SCy Schubert 		}
74541edb306SCy Schubert 
74641edb306SCy Schubert 		if (opts & OPT_VERBOSE)
74741edb306SCy Schubert 			printf("Got nat next %p ipn_dsize %d ng_sz %d\n",
74841edb306SCy Schubert 				ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz);
74941edb306SCy Schubert 		if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) {
75041edb306SCy Schubert 			perror("nat:write");
75141edb306SCy Schubert 			close(nfd);
75241edb306SCy Schubert 			free(ipnp);
75341edb306SCy Schubert 			return 1;
75441edb306SCy Schubert 		}
75541edb306SCy Schubert 		next = ipnp->ipn_next;
75641edb306SCy Schubert 	} while (ipnp && next);
75741edb306SCy Schubert 	if (ipnp != NULL)
75841edb306SCy Schubert 		free(ipnp);
75941edb306SCy Schubert 	close(nfd);
76041edb306SCy Schubert 
76141edb306SCy Schubert 	return 0;
76241edb306SCy Schubert }
76341edb306SCy Schubert 
76441edb306SCy Schubert 
765*efeb8bffSCy Schubert int writeall(char *dirname)
76641edb306SCy Schubert {
76741edb306SCy Schubert 	int fd, devfd;
76841edb306SCy Schubert 
76941edb306SCy Schubert 	if (!dirname)
77041edb306SCy Schubert 		dirname = IPF_SAVEDIR;
77141edb306SCy Schubert 
77241edb306SCy Schubert 	if (chdir(dirname)) {
77341edb306SCy Schubert 		fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname);
77441edb306SCy Schubert 		perror("chdir(IPF_SAVEDIR)");
77541edb306SCy Schubert 		return 1;
77641edb306SCy Schubert 	}
77741edb306SCy Schubert 
77841edb306SCy Schubert 	fd = opendevice(NULL);
77941edb306SCy Schubert 	if (fd == -1)
78041edb306SCy Schubert 		return 1;
78141edb306SCy Schubert 	if (setlock(fd, 1)) {
78241edb306SCy Schubert 		close(fd);
78341edb306SCy Schubert 		return 1;
78441edb306SCy Schubert 	}
78541edb306SCy Schubert 
78641edb306SCy Schubert 	devfd = opendevice(IPSTATE_NAME);
78741edb306SCy Schubert 	if (devfd == -1)
78841edb306SCy Schubert 		goto bad;
78941edb306SCy Schubert 	if (writestate(devfd, NULL))
79041edb306SCy Schubert 		goto bad;
79141edb306SCy Schubert 	close(devfd);
79241edb306SCy Schubert 
79341edb306SCy Schubert 	devfd = opendevice(IPNAT_NAME);
79441edb306SCy Schubert 	if (devfd == -1)
79541edb306SCy Schubert 		goto bad;
79641edb306SCy Schubert 	if (writenat(devfd, NULL))
79741edb306SCy Schubert 		goto bad;
79841edb306SCy Schubert 	close(devfd);
79941edb306SCy Schubert 
80041edb306SCy Schubert 	if (setlock(fd, 0)) {
80141edb306SCy Schubert 		close(fd);
80241edb306SCy Schubert 		return 1;
80341edb306SCy Schubert 	}
80441edb306SCy Schubert 
80541edb306SCy Schubert 	close(fd);
80641edb306SCy Schubert 	return 0;
80741edb306SCy Schubert 
80841edb306SCy Schubert bad:
80941edb306SCy Schubert 	setlock(fd, 0);
81041edb306SCy Schubert 	close(fd);
81141edb306SCy Schubert 	return 1;
81241edb306SCy Schubert }
81341edb306SCy Schubert 
81441edb306SCy Schubert 
815*efeb8bffSCy Schubert int readall(char *dirname)
81641edb306SCy Schubert {
81741edb306SCy Schubert 	int fd, devfd;
81841edb306SCy Schubert 
81941edb306SCy Schubert 	if (!dirname)
82041edb306SCy Schubert 		dirname = IPF_SAVEDIR;
82141edb306SCy Schubert 
82241edb306SCy Schubert 	if (chdir(dirname)) {
82341edb306SCy Schubert 		perror("chdir(IPF_SAVEDIR)");
82441edb306SCy Schubert 		return 1;
82541edb306SCy Schubert 	}
82641edb306SCy Schubert 
82741edb306SCy Schubert 	fd = opendevice(NULL);
82841edb306SCy Schubert 	if (fd == -1)
82941edb306SCy Schubert 		return 1;
83041edb306SCy Schubert 	if (setlock(fd, 1)) {
83141edb306SCy Schubert 		close(fd);
83241edb306SCy Schubert 		return 1;
83341edb306SCy Schubert 	}
83441edb306SCy Schubert 
83541edb306SCy Schubert 	devfd = opendevice(IPSTATE_NAME);
83641edb306SCy Schubert 	if (devfd == -1)
83741edb306SCy Schubert 		return 1;
83841edb306SCy Schubert 	if (readstate(devfd, NULL))
83941edb306SCy Schubert 		return 1;
84041edb306SCy Schubert 	close(devfd);
84141edb306SCy Schubert 
84241edb306SCy Schubert 	devfd = opendevice(IPNAT_NAME);
84341edb306SCy Schubert 	if (devfd == -1)
84441edb306SCy Schubert 		return 1;
84541edb306SCy Schubert 	if (readnat(devfd, NULL))
84641edb306SCy Schubert 		return 1;
84741edb306SCy Schubert 	close(devfd);
84841edb306SCy Schubert 
84941edb306SCy Schubert 	if (setlock(fd, 0)) {
85041edb306SCy Schubert 		close(fd);
85141edb306SCy Schubert 		return 1;
85241edb306SCy Schubert 	}
85341edb306SCy Schubert 
85441edb306SCy Schubert 	return 0;
85541edb306SCy Schubert }
856