kern/55984: [patch] time based firewalling support for ipfw2

Christian S.J.Peron maneo at bsdpro.com
Mon Aug 25 22:00:38 PDT 2003


>Number:         55984
>Category:       kern
>Synopsis:       [patch] time based firewalling support for ipfw2
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Aug 25 22:00:36 PDT 2003
>Closed-Date:
>Last-Modified:
>Originator:     Christian S.J. Peron
>Release:        FreeBSD 5.1-CURRENT i386
>Organization:
Seccuris Inc
>Environment:
System: FreeBSD movl 5.1-CURRENT FreeBSD 5.1-CURRENT #14: Mon Aug 25 17:22:40 CDT 2003     modulus at movl:/usr/src/sys/i386/compile/RAID0  i386


	
>Description:

I have enclosed a patch which allows ipfw2 to filter based on
the time of day. Mostly looking for approval/testers.
I have tested this patch but it may be missing something.

CAVEATS

As noted in the BUGS section of the ipfw.8 diff, if your system
shifts its time for daylight savings, firewall rules will have to
be refreshed, because the kernel is not aware of such things.

QUICK EXAMPLE

ipfw add allow ip from any to any times 09:00:00 17:00:00

Allow all IP traffic from 9:00 AM to 5:00 PM.

Thanks, enjoy!
Christian S.J. Peron

	
>How-To-Repeat:
N/A
	
>Fix:

--- sys/netinet/ip_fw.h.timeless	Mon Aug 25 00:22:54 2003
+++ sys/netinet/ip_fw.h	Mon Aug 25 17:18:34 2003
@@ -93,6 +93,7 @@
 	O_TCPACK,		/* u32 = desired seq.		*/
 	O_ICMPTYPE,		/* u32 = icmp bitmap		*/
 	O_TCPOPTS,		/* arg1 = 2*u8 bitmap		*/
+	O_TIME,			/* arg1 = from time arg2 = to time */
 
 	O_VERREVPATH,		/* none				*/
 
@@ -215,6 +216,16 @@
 	u_char addr[12];	/* dst[6] + src[6] */
 	u_char mask[12];	/* dst[6] + src[6] */
 } ipfw_insn_mac;
+
+/*
+ * This is used for the time constraint specifications.
+ */
+typedef struct _ipfw_insn_time {
+	ipfw_insn o;
+	long tzoff;
+	u_long from;
+	u_long to;
+} ipfw_insn_time;
 
 /*
  * This is used for interface match rules (recv xx, xmit xx).
--- sys/netinet/ip_fw2.c.timeless	Mon Aug 25 00:20:24 2003
+++ sys/netinet/ip_fw2.c	Mon Aug 25 17:15:24 2003
@@ -22,7 +22,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: /repoman/r/ncvs/src/sys/netinet/ip_fw2.c,v 1.37 2003/07/15 23:07:34 luigi Exp $
+ * $FreeBSD: src/sys/netinet/ip_fw2.c,v 1.37 2003/07/15 23:07:34 luigi Exp $
  */
 
 #define        DEB(x)
@@ -283,6 +283,40 @@
 	return 1;
 }
 
+/*
+ * For this example we will assume the current time is ``HH:MM:SS'' 
+ * 10:12:22
+ *
+ * f(x) = (HOURS * 3600) + (MINUTES * 60) + SECONDS
+ *      = (10 * 3600) + (12 * 60) + 22
+ *      = 36000 + 720 + 22
+ *      = 36742
+ *
+ * IF [ f(10:12:22) >= f(9:00:00) && f(10:12:22) <= (17:00:00) ]
+ *      current time (10:12:22) falls within time constraint
+ * ELSE
+ *      current time (10:12:22) does not fall in time constraint
+ * ENDIF
+ */
+
+static u_long
+ipfw_calc_time_sum(time_t T)
+{
+	u_long S, M, H, R;
+	u_long SUM, MH, MM;
+
+	R   = (T / 3600);
+	H   = (R % 24);
+	MH  = (H * 3600);
+	R   = (T / 60);
+	M   = (R % 60);
+	MM  = (M * 60);
+	S   = (T % 60);
+	SUM = (MH + MM + S);
+
+	return(SUM);
+}
+
 static int
 ipopts_match(struct ip *ip, ipfw_insn *cmd)
 {
@@ -1590,6 +1624,21 @@
 				    m->m_pkthdr.rcvif, (ipfw_insn_if *)cmd);
 				break;
 
+			case O_TIME:
+				{
+					struct timeval tm;
+					u_long from, to, sum;
+					long tzoff;
+
+					microtime(&tm);
+					tzoff = ((ipfw_insn_time *)cmd)->tzoff;
+					from = ((ipfw_insn_time *)cmd)->from;
+					to = ((ipfw_insn_time *)cmd)->to;
+					sum = ipfw_calc_time_sum(tm.tv_sec + tzoff);
+					match = (sum >= from  && sum <= to);
+				}
+				break;
+					
 			case O_MACADDR2:
 				if (args->eh != NULL) {	/* have MAC header */
 					u_int32_t *want = (u_int32_t *)
@@ -2457,6 +2506,11 @@
 			}
 			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
 			    (cmd->arg1+31)/32 )
+				goto bad_size;
+			break;
+
+		case O_TIME:
+			if (cmdlen != F_INSN_SIZE(ipfw_insn_time))
 				goto bad_size;
 			break;
 
--- sbin/ipfw/ipfw.8.timeless	Tue Jul 22 02:41:24 2003
+++ sbin/ipfw/ipfw.8	Mon Aug 25 15:38:58 2003
@@ -1,5 +1,5 @@
 .\"
-.\" $FreeBSD: /repoman/r/ncvs/src/sbin/ipfw/ipfw.8,v 1.131 2003/07/22 07:41:24 luigi Exp $
+.\" $FreeBSD: src/sbin/ipfw/ipfw.8,v 1.131 2003/07/22 07:41:24 luigi Exp $
 .\"
 .Dd August 13, 2002
 .Dt IPFW 8
@@ -1178,6 +1178,13 @@
 The absence of a particular option may be denoted
 with a
 .Ql \&! .
+.It Cm times Ar from to
+Match all packets which are processed by the firewall between
+times
+.Ar from
+and
+.Ar to .
+Time specifications must be given in ``HH:MM:SS'' format.
 .It Cm uid Ar user
 Match all TCP or UDP packets sent by or received for a
 .Ar user .
@@ -2152,6 +2159,10 @@
 applied, making the order of
 .Cm divert
 rules in the rule sequence very important.
+.Pp
+If the system clock automatically shifts for daylight savings time, any firewall
+rules which implement time constraints or time based filtering
+must be refreshed with ipfw(8).
 .Sh AUTHORS
 .An Ugen J. S. Antsilevich ,
 .An Poul-Henning Kamp ,
--- sbin/ipfw/ipfw2.c.timeless	Sun Aug 24 20:15:08 2003
+++ sbin/ipfw/ipfw2.c	Mon Aug 25 23:25:40 2003
@@ -221,6 +221,7 @@
 	TOK_TCPSEQ,
 	TOK_TCPACK,
 	TOK_TCPWIN,
+	TOK_TIME,
 	TOK_ICMPTYPES,
 	TOK_MAC,
 	TOK_MACTYPE,
@@ -326,6 +327,7 @@
 	{ "tcpseq",		TOK_TCPSEQ },
 	{ "tcpack",		TOK_TCPACK },
 	{ "tcpwin",		TOK_TCPWIN },
+	{ "times",		TOK_TIME },
 	{ "icmptype",		TOK_ICMPTYPES },
 	{ "icmptypes",		TOK_ICMPTYPES },
 	{ "dst-ip",		TOK_DSTIP },
@@ -351,6 +353,51 @@
 	{ NULL, 0 }	/* terminator */
 };
 
+static u_long
+timeconv(char *timespec)
+{
+	u_long M, H, SUM;
+	struct tm *tmp;
+	time_t t;
+	char *p;
+
+	t = time(0);
+	tmp = localtime(&t);
+
+	if ((p = strptime(timespec, "%H:%M:%S", tmp)) == 0)
+		errx(1, "time conversion failed");
+
+	if ((t = mktime(tmp)) < 0)
+		errx(1, "mktime failed");
+
+	tmp = localtime(&t);
+	H = M = SUM = 0;
+	H = tmp->tm_hour * 3600;
+	M = tmp->tm_min * 60;
+	SUM = (H + M + tmp->tm_sec);
+
+	return(SUM);
+}
+
+/*
+ * Basically do the reverse of timeconv(). Given the
+ * sum translate it into a clock.
+ */
+static void
+revtimesum(u_long T)
+{
+	u_long S, M, H, R;
+
+	R = (T / 3600);
+	H = (R % 24);
+	R = (T / 60);
+	M = (R % 60);
+	S = (T % 60);
+	printf(" %02u:%02u:%02u", H, M, S);
+
+	return;
+}
+
 static __inline uint64_t
 align_uint64(uint64_t *pll) {
 	uint64_t ret;
@@ -1067,6 +1114,22 @@
 			flags |= HAVE_MAC | HAVE_MACTYPE | HAVE_OPTIONS;
 			break;
 
+		case O_TIME:
+		    {
+			ipfw_insn_time *m = (ipfw_insn_time *)cmd;
+
+			if ((cmd->len & F_OR) && !or_block)
+				printf(" {");
+			if (cmd->len & F_NOT)
+				printf(" not");
+
+			printf(" times");
+			revtimesum(m->from);
+			printf(" to");
+			revtimesum(m->to);
+		    }
+			break;
+
 		case O_IP_SRC:
 		case O_IP_SRC_MASK:
 		case O_IP_SRC_ME:
@@ -2617,6 +2680,36 @@
 }
 
 static ipfw_insn *
+add_time_constraint(ipfw_insn *cmd, int ac, char *av[])
+{
+	ipfw_insn_time *fw_time;
+	time_t t;
+	struct tm *tmp;
+
+	if (ac < 2)
+		errx(EX_DATAERR, "time from to");
+
+	cmd->opcode = O_TIME;
+	cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_time);
+
+	t = time(0);
+	tmp = localtime(&t);
+	fw_time = (ipfw_insn_time *)cmd;
+	fw_time->from = timeconv(av[0]);
+	fw_time->to = timeconv(av[1]);
+
+	if (fw_time->from > fw_time->to)
+		errx(EX_USAGE, "`from' timespec is later than `to'");
+
+	if (fw_time->from == fw_time->to)
+		errx(EX_USAGE, "time specifications are equal.");
+
+	fw_time->tzoff = tmp->tm_gmtoff;
+
+	return(cmd);
+}
+ 
+static ipfw_insn *
 add_mactype(ipfw_insn *cmd, int ac, char *av)
 {
 	if (ac < 1)
@@ -3391,6 +3484,13 @@
 			if (!add_mactype(cmd, ac, *av))
 				errx(EX_DATAERR, "invalid mac type %s", *av);
 			ac--; av++;
+			break;
+
+		case TOK_TIME:
+			if (add_time_constraint(cmd, ac, av)) {
+				ac -= 2;
+				av += 2;
+			}
 			break;
 
 		case TOK_VERREVPATH:
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list