Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 5 Jun 2001 10:45:23 +0400 (MSD)
From:      avn@any.ru
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   bin/27887: ipfw 'backup' option proposal
Message-ID:  <200106050645.f556jNX04851@srv2.any>

next in thread | raw e-mail | index | archive | help

>Number:         27887
>Category:       bin
>Synopsis:       ipfw 'backup' option proposal
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jun 04 23:50:01 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     Alexey V. Neyman
>Release:        FreeBSD 4.3-STABLE i386
>Organization:
http://www.any.ru/
>Environment:
System: FreeBSD srv2.any 4.3-STABLE FreeBSD 4.3-STABLE #2: Thu May 17 19:01:42 MSD 2001 toor@srv2.any:/usr2/obj/usr2/src/sys/SRV2 i386

>Description:
	Usage of ipfw on remote systems is often dangerous, and handbook
	explicitly warns about this. IMO it can be useful to have a 'backup'
	option to ipfw, which would restore previous ruleset in case that
	user locked himself out. It saves the ruleset, performs requested
	changes to ipfw and asks a user if he is still on-line. In case of
	disconnection, timeout of 15 seconds, or signal delivery, it restores
	previous ruleset. As for now, AFAIK, there is no interface to introduce
	dynamic rules directly, so it restores only static ruleset, and does
	not restore pipes too. But, it should be enough in most cases to
	allow user get back again.

	Patch below is against 4.3-STABLE, I was not able to test against
	-CURRENT for now, I will probably in a week.
>How-To-Repeat:
	This is a change-request.
>Fix:

--- ipfw.c.orig	Tue Feb 20 17:05:37 2001
+++ ipfw.c	Tue May 29 23:43:22 2001
@@ -67,6 +67,7 @@
 		do_pipe,			/* this cmd refers to a pipe */
 		do_sort,			/* field to sort results (0=no) */
 		verbose;
+void		*rules_backup;			/* ruleset backup, if not NULL */
 
 struct icmpcode {
 	int	code;
@@ -94,6 +95,8 @@
 };
 
 static void show_usage(const char *fmt, ...);
+static void backup_rules();
+static void restore_rules();
 
 static int
 mask_bits(struct in_addr m_ad)
@@ -602,12 +605,32 @@
 }
 
 static void
+get_rules(data, nbytes)
+	void **data;
+	int *nbytes;
+{
+	const int unit = do_pipe ? sizeof(struct ip_fw) : sizeof(struct dn_pipe);
+	const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET;
+	int nalloc = unit;
+	*nbytes = nalloc ;
+
+	while (*nbytes >= nalloc) {
+		nalloc = nalloc * 2 + 200;
+		*nbytes = nalloc ;
+		if ((*data = realloc(*data, *nbytes)) == NULL)
+			err(EX_OSERR, "realloc");
+		if (getsockopt(s, IPPROTO_IP, ocmd, *data, nbytes) < 0)
+			err(EX_OSERR, "getsockopt(IP_%s_GET)",
+			    do_pipe ? "DUMMYNET" : "FW");
+	}
+}
+
+static void
 list(ac, av)
 	int	ac;
 	char 	**av;
 {
 	struct ip_fw *rules;
-	struct dn_pipe *pipes;
 	void *data = NULL;
 	int pcwidth = 0;
 	int bcwidth = 0;
@@ -615,22 +638,7 @@
 	int nbytes;
 
 	/* get rules or pipes from kernel, resizing array as necessary */
-	{
-		const int unit = do_pipe ? sizeof(*pipes) : sizeof(*rules);
-		const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET;
-		int nalloc = unit;
-		nbytes = nalloc ;
-
-		while (nbytes >= nalloc) {
-			nalloc = nalloc * 2 + 200;
-			nbytes = nalloc ;
-			if ((data = realloc(data, nbytes)) == NULL)
-				err(EX_OSERR, "realloc");
-			if (getsockopt(s, IPPROTO_IP, ocmd, data, &nbytes) < 0)
-				err(EX_OSERR, "getsockopt(IP_%s_GET)",
-				    do_pipe ? "DUMMYNET" : "FW");
-		}
-	}
+	get_rules(&data, &nbytes);
 
 	/* display requested pipes */
 	if (do_pipe) {
@@ -857,6 +865,7 @@
 "    droptail\n"
 );
 
+	restore_rules();
 	exit(EX_USAGE);
 }
 
@@ -2069,6 +2078,81 @@
 	}
 }
 
+static void
+backup_rules()
+{
+	int nbytes, saved_do_pipe;
+
+	if (!isatty(STDIN_FILENO))
+		return;
+	saved_do_pipe = do_pipe;
+	do_pipe = 0;
+	get_rules(&rules_backup, &nbytes);
+	do_pipe = saved_do_pipe;
+}
+
+static void
+sighnd(signo)
+	int signo;
+{
+}
+
+static void
+restore_rules()
+{
+	struct ip_fw *rules;
+	int i, sz, c;
+	fd_set fdr;
+	struct timeval tv;
+
+	if (rules_backup == NULL)
+		return;
+
+	/* Ask the user */
+	printf("Everything ok? [yn] ");
+	FD_ZERO(&fdr);
+	FD_SET(STDIN_FILENO, &fdr);
+	tv.tv_sec = 15;
+	tv.tv_usec = 0;
+	signal(SIGHUP, sighnd);
+	signal(SIGINT, sighnd);
+	signal(SIGTERM, sighnd);
+	if (select(STDIN_FILENO + 1, &fdr, NULL, NULL, &tv) < 0
+	|| !FD_ISSET(STDIN_FILENO, &fdr)) {
+		printf("\n");
+		goto restore;
+	}
+
+	do {
+		fflush(stdout);
+		c = toupper(getc(stdin));
+		while (c != '\n' && getc(stdin) != '\n')
+			if (feof(stdin))
+				goto restore;
+	} while (c != 'Y' && c != 'N');
+
+	printf("\n");
+	if (c == 'Y') {
+		free(rules_backup);
+		rules_backup = NULL;
+		return;
+	}
+
+restore:
+	if (setsockopt(s, IPPROTO_IP, IP_FW_FLUSH, NULL, 0) < 0)
+		err(EX_UNAVAILABLE, "setsockopt(IP_FW_FLUSH)");
+
+	rules = (struct ip_fw *)rules_backup;
+	for (i = 0; rules[i].fw_number < 65535; i++) {
+		sz = sizeof(*rules);
+		if (getsockopt(s, IPPROTO_IP, IP_FW_ADD, rules + i, &sz) < 0)
+			err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
+	}
+	printf("Restored previous ruleset.\n");
+	free(rules_backup);
+	rules_backup = NULL;
+}
+
 static int
 ipfw_main(ac,av)
 	int 	ac;
@@ -2089,7 +2173,7 @@
 	do_force = !isatty(STDIN_FILENO);
 
 	optind = optreset = 1;
-	while ((ch = getopt(ac, av, "s:afqtvN")) != -1)
+	while ((ch = getopt(ac, av, "s:abfqtvN")) != -1)
 	switch(ch) {
 		case 's': /* sort */
 			do_sort= atoi(optarg);
@@ -2097,6 +2181,9 @@
 		case 'a':
 			do_acct=1;
 			break;
+		case 'b':
+			backup_rules();
+			break;
 		case 'f':
 			do_force=1;
 			break;
@@ -2211,6 +2298,7 @@
 		err(EX_UNAVAILABLE, "socket");
 
 	setbuf(stdout,0);
+	rules_backup = NULL;
 
 	/*
 	 * this is a nasty check on the last argument!!!
@@ -2222,7 +2310,7 @@
 		qflag = pflag = i = 0;
 		lineno = 0;
 
-		while ((c = getopt(ac, av, "D:U:p:q")) != -1)
+		while ((c = getopt(ac, av, "D:U:bp:q")) != -1)
 			switch(c) {
 			case 'D':
 				if (!pflag)
@@ -2244,6 +2332,10 @@
 				args[i++] = optarg;
 				break;
 
+			case 'b':
+				backup_rules();
+				break;
+
 			case 'p':
 				pflag = 1;
 				cmd = optarg;
@@ -2345,5 +2437,7 @@
 
 	} else
 		ipfw_main(ac,av);
+
+	restore_rules();
 	return EX_OK;
 }
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200106050645.f556jNX04851>