add time match support
authorJo-Philipp Wich <jow@openwrt.org>
Thu, 21 Feb 2013 21:42:01 +0000 (22:42 +0100)
committerJo-Philipp Wich <jow@openwrt.org>
Thu, 21 Feb 2013 22:02:45 +0000 (23:02 +0100)
options.c
options.h
redirects.c
rules.c

index c605260..9870e91 100644 (file)
--- a/options.c
+++ b/options.c
@@ -518,6 +518,160 @@ fw3_parse_ipset_datatype(void *ptr, const char *val)
        return false;
 }
 
+bool
+fw3_parse_date(void *ptr, const char *val)
+{
+       unsigned int year = 1970, mon = 1, day = 1, hour = 0, min = 0, sec = 0;
+       struct tm tm = { 0 };
+       char *p;
+
+       year = strtoul(val, &p, 10);
+       if ((*p != '-' && *p) || year < 1970 || year > 2038)
+               goto fail;
+       else if (!*p)
+               goto ret;
+
+       mon = strtoul(++p, &p, 10);
+       if ((*p != '-' && *p) || mon > 12)
+               goto fail;
+       else if (!*p)
+               goto ret;
+
+       day = strtoul(++p, &p, 10);
+       if ((*p != 'T' && *p) || day > 31)
+               goto fail;
+       else if (!*p)
+               goto ret;
+
+       hour = strtoul(++p, &p, 10);
+       if ((*p != ':' && *p) || hour > 23)
+               goto fail;
+       else if (!*p)
+               goto ret;
+
+       min = strtoul(++p, &p, 10);
+       if ((*p != ':' && *p) || min > 59)
+               goto fail;
+       else if (!*p)
+               goto ret;
+
+       sec = strtoul(++p, &p, 10);
+       if (*p || sec > 59)
+               goto fail;
+
+ret:
+       tm.tm_year = year - 1900;
+       tm.tm_mon  = mon - 1;
+       tm.tm_mday = day;
+       tm.tm_hour = hour;
+       tm.tm_min  = min;
+       tm.tm_sec  = sec;
+
+       if (mktime(&tm) >= 0)
+       {
+               *((struct tm *)ptr) = tm;
+               return true;
+       }
+
+fail:
+       return false;
+}
+
+bool
+fw3_parse_time(void *ptr, const char *val)
+{
+       unsigned int hour = 0, min = 0, sec = 0;
+       char *p;
+
+       hour = strtoul(val, &p, 10);
+       if (*p != ':' || hour > 23)
+               goto fail;
+
+       min = strtoul(++p, &p, 10);
+       if ((*p != ':' && *p) || min > 59)
+               goto fail;
+       else if (!*p)
+               goto ret;
+
+       sec = strtoul(++p, &p, 10);
+       if (*p || sec > 59)
+               goto fail;
+
+ret:
+       *((int *)ptr) = 60 * 60 * hour + 60 * min + sec;
+       return true;
+
+fail:
+       return false;
+}
+
+bool
+fw3_parse_weekdays(void *ptr, const char *val)
+{
+       unsigned int w;
+       char *p;
+
+       if (*val == '!')
+       {
+               setbit(*(uint8_t *)ptr, 0);
+               while (isspace(*++val));
+       }
+
+       for (p = strtok((char *)val, " \t"); p; p = strtok(NULL, " \t"))
+       {
+               if (!strncasecmp(p, "monday", strlen(p)))
+                       w = 1;
+               else if (!strncasecmp(p, "tuesday", strlen(p)))
+                       w = 2;
+               else if (!strncasecmp(p, "wednesday", strlen(p)))
+                       w = 3;
+               else if (!strncasecmp(p, "thursday", strlen(p)))
+                       w = 4;
+               else if (!strncasecmp(p, "friday", strlen(p)))
+                       w = 5;
+               else if (!strncasecmp(p, "saturday", strlen(p)))
+                       w = 6;
+               else if (!strncasecmp(p, "sunday", strlen(p)))
+                       w = 7;
+               else
+               {
+                       w = strtoul(p, &p, 10);
+
+                       if (*p || w < 1 || w > 7)
+                               return false;
+               }
+
+               setbit(*(uint8_t *)ptr, w);
+       }
+
+       return true;
+}
+
+bool
+fw3_parse_monthdays(void *ptr, const char *val)
+{
+       unsigned int d;
+       char *p;
+
+       if (*val == '!')
+       {
+               setbit(*(uint32_t *)ptr, 0);
+               while (isspace(*++val));
+       }
+
+       for (p = strtok((char *)val, " \t"); p; p = strtok(NULL, " \t"))
+       {
+               d = strtoul(p, &p, 10);
+
+               if (*p || d < 1 || d > 31)
+                       return false;
+
+               setbit(*(uint32_t *)ptr, d);
+       }
+
+       return true;
+}
+
 
 void
 fw3_parse_options(void *s, const struct fw3_option *opts,
@@ -810,6 +964,84 @@ fw3_format_ipset(struct fw3_ipset *ipset, bool invert)
 }
 
 void
+fw3_format_time(struct fw3_time *time)
+{
+       int i;
+       struct tm empty = { 0 };
+       char buf[sizeof("9999-99-99T23:59:59\0")];
+       bool d1 = memcmp(&time->datestart, &empty, sizeof(empty));
+       bool d2 = memcmp(&time->datestop, &empty, sizeof(empty));
+       bool first;
+
+       if (!d1 && !d2 && !time->timestart && !time->timestop &&
+           !(time->monthdays & 0xFFFFFFFE) && !(time->weekdays & 0xFE))
+       {
+               return;
+       }
+
+       fw3_pr(" -m time");
+
+       if (time->utc)
+               fw3_pr(" --utc");
+
+       if (d1)
+       {
+               strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &time->datestart);
+               fw3_pr(" --datestart %s", buf);
+       }
+
+       if (d2)
+       {
+               strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &time->datestop);
+               fw3_pr(" --datestop %s", buf);
+       }
+
+       if (time->timestart)
+       {
+               fw3_pr(" --timestart %02d:%02d:%02d",
+                      time->timestart / 3600,
+                      time->timestart % 3600 / 60,
+                      time->timestart % 60);
+       }
+
+       if (time->timestop)
+       {
+               fw3_pr(" --timestop %02d:%02d:%02d",
+                      time->timestop / 3600,
+                      time->timestop % 3600 / 60,
+                      time->timestop % 60);
+       }
+
+       if (time->monthdays & 0xFFFFFFFE)
+       {
+               fw3_pr(" %s--monthdays", (time->monthdays & 1) ? "! " : "");
+
+               for (i = 1, first = true; i < 32; i++)
+               {
+                       if (hasbit(time->monthdays, i))
+                       {
+                               fw3_pr("%c%u", first ? ' ' : ',', i);
+                               first = false;
+                       }
+               }
+       }
+
+       if (time->weekdays & 0xFE)
+       {
+               fw3_pr(" %s--weekdays", (time->weekdays & 1) ? "! " : "");
+
+               for (i = 1, first = true; i < 8; i++)
+               {
+                       if (hasbit(time->weekdays, i))
+                       {
+                               fw3_pr("%c%u", first ? ' ' : ',', i);
+                               first = false;
+                       }
+               }
+       }
+}
+
+void
 __fw3_format_comment(const char *comment, ...)
 {
        va_list ap;
index 2209cbe..fe9816e 100644 (file)
--- a/options.h
+++ b/options.h
@@ -35,6 +35,8 @@
 #include <netinet/in.h>
 #include <netinet/ether.h>
 
+#include <time.h>
+
 #include <uci.h>
 
 #include <libubox/list.h>
@@ -196,6 +198,17 @@ struct fw3_limit
        enum fw3_limit_unit unit;
 };
 
+struct fw3_time
+{
+       bool utc;
+       struct tm datestart;
+       struct tm datestop;
+       uint32_t timestart;
+       uint32_t timestop;
+       uint32_t monthdays; /* bit 0 is invert + 1 .. 31 */
+       uint8_t weekdays;   /* bit 0 is invert + 1 .. 7 */
+};
+
 struct fw3_defaults
 {
        enum fw3_target policy_input;
@@ -286,9 +299,10 @@ struct fw3_rule
 
        struct list_head icmp_type;
 
-       enum fw3_target target;
-
        struct fw3_limit limit;
+       struct fw3_time time;
+
+       enum fw3_target target;
 
        const char *extra;
 };
@@ -322,6 +336,8 @@ struct fw3_redirect
        struct fw3_address ip_redir;
        struct fw3_port port_redir;
 
+       struct fw3_time time;
+
        enum fw3_target target;
 
        const char *extra;
@@ -416,9 +432,15 @@ bool fw3_parse_port(void *ptr, const char *val);
 bool fw3_parse_family(void *ptr, const char *val);
 bool fw3_parse_icmptype(void *ptr, const char *val);
 bool fw3_parse_protocol(void *ptr, const char *val);
+
 bool fw3_parse_ipset_method(void *ptr, const char *val);
 bool fw3_parse_ipset_datatype(void *ptr, const char *val);
 
+bool fw3_parse_date(void *ptr, const char *val);
+bool fw3_parse_time(void *ptr, const char *val);
+bool fw3_parse_weekdays(void *ptr, const char *val);
+bool fw3_parse_monthdays(void *ptr, const char *val);
+
 void fw3_parse_options(void *s, const struct fw3_option *opts,
                        struct uci_section *section);
 
@@ -430,6 +452,7 @@ void fw3_format_protocol(struct fw3_protocol *proto, enum fw3_family family);
 void fw3_format_icmptype(struct fw3_icmptype *icmp, enum fw3_family family);
 void fw3_format_limit(struct fw3_limit *limit);
 void fw3_format_ipset(struct fw3_ipset *ipset, bool invert);
+void fw3_format_time(struct fw3_time *time);
 
 void __fw3_format_comment(const char *comment, ...);
 #define fw3_format_comment(...) __fw3_format_comment(__VA_ARGS__, NULL)
index 51c764f..2aa6664 100644 (file)
 
 
 const struct fw3_option fw3_redirect_opts[] = {
-       FW3_OPT("name",                string,   redirect,     name),
-       FW3_OPT("family",              family,   redirect,     family),
+       FW3_OPT("name",                string,    redirect,     name),
+       FW3_OPT("family",              family,    redirect,     family),
 
-       FW3_OPT("src",                 device,   redirect,     src),
-       FW3_OPT("dest",                device,   redirect,     dest),
+       FW3_OPT("src",                 device,    redirect,     src),
+       FW3_OPT("dest",                device,    redirect,     dest),
 
-       FW3_OPT("ipset",               device,   redirect,     ipset),
+       FW3_OPT("ipset",               device,    redirect,     ipset),
 
-       FW3_LIST("proto",              protocol, redirect,     proto),
+       FW3_LIST("proto",              protocol,  redirect,     proto),
 
-       FW3_OPT("src_ip",              address,  redirect,     ip_src),
-       FW3_LIST("src_mac",            mac,      redirect,     mac_src),
-       FW3_OPT("src_port",            port,     redirect,     port_src),
+       FW3_OPT("src_ip",              address,   redirect,     ip_src),
+       FW3_LIST("src_mac",            mac,       redirect,     mac_src),
+       FW3_OPT("src_port",            port,      redirect,     port_src),
 
-       FW3_OPT("src_dip",             address,  redirect,     ip_dest),
-       FW3_OPT("src_dport",           port,     redirect,     port_dest),
+       FW3_OPT("src_dip",             address,   redirect,     ip_dest),
+       FW3_OPT("src_dport",           port,      redirect,     port_dest),
 
-       FW3_OPT("dest_ip",             address,  redirect,     ip_redir),
-       FW3_OPT("dest_port",           port,     redirect,     port_redir),
+       FW3_OPT("dest_ip",             address,   redirect,     ip_redir),
+       FW3_OPT("dest_port",           port,      redirect,     port_redir),
 
-       FW3_OPT("extra",               string,   redirect,     extra),
+       FW3_OPT("extra",               string,    redirect,     extra),
 
-       FW3_OPT("reflection",          bool,     redirect,     reflection),
+       FW3_OPT("utc_time",            bool,      redirect,     time.utc),
+       FW3_OPT("start_date",          date,      redirect,     time.datestart),
+       FW3_OPT("stop_date",           date,      redirect,     time.datestop),
+       FW3_OPT("start_time",          time,      redirect,     time.timestart),
+       FW3_OPT("stop_time",           time,      redirect,     time.timestop),
+       FW3_OPT("weekdays",            weekdays,  redirect,     time.weekdays),
+       FW3_OPT("monthdays",           monthdays, redirect,     time.monthdays),
 
-       FW3_OPT("target",              target,   redirect,     target),
+       FW3_OPT("reflection",          bool,      redirect,     reflection),
+
+       FW3_OPT("target",              target,    redirect,     target),
 
        { }
 };
@@ -364,6 +372,7 @@ print_redirect(enum fw3_table table, enum fw3_family family,
                        }
 
                        fw3_format_mac(mac);
+                       fw3_format_time(&redir->time);
                        fw3_format_extra(redir->extra);
                        fw3_format_comment(redir->name);
                        print_target_nat(redir);
@@ -376,6 +385,7 @@ print_redirect(enum fw3_table table, enum fw3_family family,
                        fw3_format_src_dest(&redir->ip_src, &redir->ip_redir);
                        fw3_format_sport_dport(&redir->port_src, &redir->port_redir);
                        fw3_format_mac(mac);
+                       fw3_format_time(&redir->time);
                        fw3_format_extra(redir->extra);
                        fw3_format_comment(redir->name);
                        print_target_filter(redir);
@@ -422,6 +432,7 @@ print_redirect(enum fw3_table table, enum fw3_family family,
                                        fw3_format_protocol(proto, family);
                                        fw3_format_src_dest(int_addr, ext_addr);
                                        fw3_format_sport_dport(NULL, &redir->port_dest);
+                                       fw3_format_time(&redir->time);
                                        fw3_format_comment(redir->name, " (reflection)");
                                        print_snat_dnat(FW3_TARGET_DNAT,
                                                        &redir->ip_redir, &redir->port_redir);
@@ -430,6 +441,7 @@ print_redirect(enum fw3_table table, enum fw3_family family,
                                        fw3_format_protocol(proto, family);
                                        fw3_format_src_dest(int_addr, &redir->ip_redir);
                                        fw3_format_sport_dport(NULL, &redir->port_redir);
+                                       fw3_format_time(&redir->time);
                                        fw3_format_comment(redir->name, " (reflection)");
                                        print_snat_dnat(FW3_TARGET_SNAT, ext_addr, NULL);
                                }
@@ -439,6 +451,7 @@ print_redirect(enum fw3_table table, enum fw3_family family,
                                        fw3_format_protocol(proto, family);
                                        fw3_format_src_dest(int_addr, &redir->ip_redir);
                                        fw3_format_sport_dport(NULL, &redir->port_redir);
+                                       fw3_format_time(&redir->time);
                                        fw3_format_comment(redir->name, " (reflection)");
                                        fw3_pr(" -j zone_%s_dest_ACCEPT\n", redir->dest.name);
                                }
diff --git a/rules.c b/rules.c
index ab094bb..e733cd9 100644 (file)
--- a/rules.c
+++ b/rules.c
 
 
 const struct fw3_option fw3_rule_opts[] = {
-       FW3_OPT("name",                string,   rule,     name),
-       FW3_OPT("family",              family,   rule,     family),
+       FW3_OPT("name",                string,    rule,     name),
+       FW3_OPT("family",              family,    rule,     family),
 
-       FW3_OPT("src",                 device,   rule,     src),
-       FW3_OPT("dest",                device,   rule,     dest),
+       FW3_OPT("src",                 device,    rule,     src),
+       FW3_OPT("dest",                device,    rule,     dest),
 
-       FW3_OPT("ipset",               device,   rule,     ipset),
+       FW3_OPT("ipset",               device,    rule,     ipset),
 
-       FW3_LIST("proto",              protocol, rule,     proto),
+       FW3_LIST("proto",              protocol,  rule,     proto),
 
-       FW3_LIST("src_ip",             address,  rule,     ip_src),
-       FW3_LIST("src_mac",            mac,      rule,     mac_src),
-       FW3_LIST("src_port",           port,     rule,     port_src),
+       FW3_LIST("src_ip",             address,   rule,     ip_src),
+       FW3_LIST("src_mac",            mac,       rule,     mac_src),
+       FW3_LIST("src_port",           port,      rule,     port_src),
 
-       FW3_LIST("dest_ip",            address,  rule,     ip_dest),
-       FW3_LIST("dest_port",          port,     rule,     port_dest),
+       FW3_LIST("dest_ip",            address,   rule,     ip_dest),
+       FW3_LIST("dest_port",          port,      rule,     port_dest),
 
-       FW3_LIST("icmp_type",          icmptype, rule,     icmp_type),
-       FW3_OPT("extra",               string,   rule,     extra),
+       FW3_LIST("icmp_type",          icmptype,  rule,     icmp_type),
+       FW3_OPT("extra",               string,    rule,     extra),
 
-       FW3_OPT("limit",               limit,    rule,     limit),
-       FW3_OPT("limit_burst",         int,      rule,     limit.burst),
+       FW3_OPT("limit",               limit,     rule,     limit),
+       FW3_OPT("limit_burst",         int,       rule,     limit.burst),
 
-       FW3_OPT("target",              target,   rule,     target),
+       FW3_OPT("utc_time",            bool,      rule,     time.utc),
+       FW3_OPT("start_date",          date,      rule,     time.datestart),
+       FW3_OPT("stop_date",           date,      rule,     time.datestop),
+       FW3_OPT("start_time",          time,      rule,     time.timestart),
+       FW3_OPT("stop_time",           time,      rule,     time.timestop),
+       FW3_OPT("weekdays",            weekdays,  rule,     time.weekdays),
+       FW3_OPT("monthdays",           monthdays, rule,     time.monthdays),
+
+       FW3_OPT("target",              target,    rule,     target),
 
        { }
 };
@@ -242,6 +250,7 @@ print_rule(enum fw3_table table, enum fw3_family family,
        fw3_format_icmptype(icmptype, family);
        fw3_format_mac(mac);
        fw3_format_limit(&rule->limit);
+       fw3_format_time(&rule->time);
        fw3_format_extra(rule->extra);
        fw3_format_comment(rule->name);
        print_target(rule);