#include <netdb.h>
#include <string.h>
#include <stdlib.h>
+#include <stddef.h> /* for 'offsetof' */
#include <getopt.h>
#include <iptables.h>
{
printf(
"TIME v%s options:\n"
-" --timestart value --timestop value --days listofdays\n"
-" timestart value : HH:MM\n"
-" timestop value : HH:MM\n"
-" listofdays value: a list of days to apply -> ie. Mon,Tue,Wed,Thu,Fri. Case sensitive\n",
+" [ --timestart value ] [ --timestop value] [ --days listofdays ] [ --datestart value ] [ --datestop value ]\n"
+" timestart value : HH:MM (default 00:00)\n"
+" timestop value : HH:MM (default 23:59)\n"
+" Note: daylight savings time changes are not tracked\n"
+" listofdays value: a list of days to apply\n"
+" from Mon,Tue,Wed,Thu,Fri,Sat,Sun\n"
+" Coma speparated, no space, case sensitive.\n"
+" Defaults to all days.\n"
+" datestart value : YYYY[:MM[:DD[:hh[:mm[:ss]]]]]\n"
+" If any of month, day, hour, minute or second is\n"
+" not specified, then defaults to their smallest\n"
+" 1900 <= YYYY < 2037\n"
+" 1 <= MM <= 12\n"
+" 1 <= DD <= 31\n"
+" 0 <= hh <= 23\n"
+" 0 <= mm <= 59\n"
+" 0 <= ss <= 59\n"
+" datestop value : YYYY[:MM[:DD[:hh[:mm[:ss]]]]]\n"
+" If the whole option is ommited, default to never stop\n"
+" If any of month, day, hour, minute or second is\n"
+" not specified, then default to their smallest\n",
IPTABLES_VERSION);
}
{ "timestart", 1, 0, '1' },
{ "timestop", 1, 0, '2' },
{ "days", 1, 0, '3'},
+ { "datestart", 1, 0, '4' },
+ { "datestop", 1, 0, '5' },
{0}
};
static void
init(struct ipt_entry_match *m, unsigned int *nfcache)
{
- /* caching not yet implemented */
- *nfcache |= NFC_UNKNOWN;
+ struct ipt_time_info *info = (struct ipt_time_info *)m->data;
globaldays = 0;
+ /* By default, we match on everyday */
+ info->days_match = 127;
+ /* By default, we match on every hour:min of the day */
+ info->time_start = 0;
+ info->time_stop = 1439; /* (23*60+59 = 1439 */
+ /* By default, we don't have any date-begin or date-end boundaries */
+ info->date_start = 0;
+ info->date_stop = LONG_MAX;
}
/**
return 1;
}
+static int
+parse_number(char *str, int num_min, int num_max, int *number)
+{
+ /* if the number starts with 0, replace it with a space else
+ string_to_number() will interpret it as octal !! */
+ if (strlen(str) == 0)
+ return 0;
+
+ if ((str[0] == '0') && (str[1] != '\0'))
+ str[0] = ' ';
+
+ return string_to_number(str, num_min, num_max, number);
+}
+
static void
-parse_time_string(unsigned int *hour, unsigned int *minute, const char *time)
+parse_time_string(int *hour, int *minute, const char *time)
{
char *hours;
char *minutes;
-
hours = (char *)malloc(3);
minutes = (char *)malloc(3);
- bzero((void *)hours, 3);
- bzero((void *)minutes, 3);
+ memset(hours, 0, 3);
+ memset(minutes, 0, 3);
- if (split_time(&hours, &minutes, time) == 1)
+ if (split_time((char **)&hours, (char **)&minutes, time) == 1)
{
- /* if the number starts with 0, replace it with a space else
- this string_to_number will interpret it as octal !! */
- if ((hours[0] == '0') && (hours[1] != '\0'))
- hours[0] = ' ';
- if ((minutes[0] == '0') && (minutes[1] != '\0'))
- minutes[0] = ' ';
-
- if((string_to_number(hours, 0, 23, hour) == -1) ||
- (string_to_number(minutes, 0, 59, minute) == -1)) {
- *hour = *minute = (-1);
+ *hour = 0;
+ *minute = 0;
+ if ((parse_number((char *)hours, 0, 23, hour) != -1) &&
+ (parse_number((char *)minutes, 0, 59, minute) != -1))
+ {
+ free(hours);
+ free(minutes);
+ return;
}
}
- if ((*hour != (-1)) && (*minute != (-1))) {
- free(hours);
- free(minutes);
- return;
- }
+
+ free(hours);
+ free(minutes);
/* If we are here, there was a problem ..*/
exit_error(PARAMETER_PROBLEM,
}
}
+static int
+parse_date_field(const char *str_to_parse, int str_to_parse_s, int start_pos,
+ char *dest, int *next_pos)
+{
+ unsigned char found_value = 0;
+ unsigned char found_column = 0;
+ int i;
+
+ for (i=0; i<2; i++)
+ {
+ if ((i+start_pos) >= str_to_parse_s) /* don't exit boundaries of the string.. */
+ break;
+ if (str_to_parse[i+start_pos] == ':')
+ found_column = 1;
+ else
+ {
+ found_value = 1;
+ dest[i] = str_to_parse[i+start_pos];
+ }
+ }
+ if (found_value == 0)
+ return 0;
+ *next_pos = i + start_pos;
+ if (found_column == 0)
+ ++(*next_pos);
+ return 1;
+}
+
+static int
+split_date(char *year, char *month, char *day,
+ char *hour, char *minute, char *second,
+ const char *str_to_parse)
+{
+ int i;
+ unsigned char found_column = 0;
+ int str_to_parse_s = strlen(str_to_parse);
+
+ /* Check the length of the string */
+ if ((str_to_parse_s > 19) || /* YYYY:MM:DD:HH:MM:SS */
+ (str_to_parse_s < 4)) /* YYYY*/
+ return 0;
+
+ /* Clear the buffers */
+ memset(year, 0, 4);
+ memset(month, 0, 2);
+ memset(day, 0, 2);
+ memset(hour, 0, 2);
+ memset(minute, 0, 2);
+ memset(second, 0, 2);
+
+ /* parse the year YYYY */
+ found_column = 0;
+ for (i=0; i<5; i++)
+ {
+ if (i >= str_to_parse_s)
+ break;
+ if (str_to_parse[i] == ':')
+ {
+ found_column = 1;
+ break;
+ }
+ else
+ year[i] = str_to_parse[i];
+ }
+ if (found_column == 1)
+ ++i;
+
+ /* parse the month if it exists */
+ if (! parse_date_field(str_to_parse, str_to_parse_s, i, month, &i))
+ return 1;
+
+ if (! parse_date_field(str_to_parse, str_to_parse_s, i, day, &i))
+ return 1;
+
+ if (! parse_date_field(str_to_parse, str_to_parse_s, i, hour, &i))
+ return 1;
+
+ if (! parse_date_field(str_to_parse, str_to_parse_s, i, minute, &i))
+ return 1;
+
+ parse_date_field(str_to_parse, str_to_parse_s, i, second, &i);
+
+ /* if we are here, format should be ok. */
+ return 1;
+}
+
+static time_t
+parse_date_string(const char *str_to_parse)
+{
+ char year[5];
+ char month[3];
+ char day[3];
+ char hour[3];
+ char minute[3];
+ char second[3];
+ struct tm t;
+ time_t temp_time;
+
+ memset(year, 0, 5);
+ memset(month, 0, 3);
+ memset(day, 0, 3);
+ memset(hour, 0, 3);
+ memset(minute, 0, 3);
+ memset(second, 0, 3);
+
+ if (split_date(year, month, day, hour, minute, second, str_to_parse) == 1)
+ {
+ memset((void *)&t, 0, sizeof(struct tm));
+ t.tm_isdst = -1;
+ t.tm_mday = 1;
+ if (!((parse_number(year, 1900, 2037, &(t.tm_year)) == -1) ||
+ (parse_number(month, 1, 12, &(t.tm_mon)) == -1) ||
+ (parse_number(day, 1, 31, &(t.tm_mday)) == -1) ||
+ (parse_number(hour, 0, 9999, &(t.tm_hour)) == -1) ||
+ (parse_number(minute, 0, 59, &(t.tm_min)) == -1) ||
+ (parse_number(second, 0, 59, &(t.tm_sec)) == -1)))
+ {
+ t.tm_year -= 1900;
+ --(t.tm_mon);
+ temp_time = mktime(&t);
+ if (temp_time != -1)
+ return temp_time;
+ }
+ }
+ exit_error(PARAMETER_PROBLEM,
+ "invalid date `%s' specified, should be YYYY[:MM[:DD[:hh[:mm[:ss]]]]] format", str_to_parse);
+}
+
#define IPT_TIME_START 0x01
#define IPT_TIME_STOP 0x02
#define IPT_TIME_DAYS 0x04
-
+#define IPT_DATE_START 0x08
+#define IPT_DATE_STOP 0x10
/* Function which parses command options; returns true if it
ate an option */
{
struct ipt_time_info *timeinfo = (struct ipt_time_info *)(*match)->data;
int hours, minutes;
+ time_t temp_date;
switch (c)
{
timeinfo->days_match = globaldays;
*flags |= IPT_TIME_DAYS;
break;
+
+ /* datestart */
+ case '4':
+ if (invert)
+ exit_error(PARAMETER_PROBLEM,
+ "unexpected '!' with --datestart");
+ if (*flags & IPT_DATE_START)
+ exit_error(PARAMETER_PROBLEM,
+ "Can't specify --datestart twice");
+ temp_date = parse_date_string(optarg);
+ timeinfo->date_start = temp_date;
+ *flags |= IPT_DATE_START;
+ break;
+
+ /* datestop*/
+ case '5':
+ if (invert)
+ exit_error(PARAMETER_PROBLEM,
+ "unexpected '!' with --datestop");
+ if (*flags & IPT_DATE_STOP)
+ exit_error(PARAMETER_PROBLEM,
+ "Can't specify --datestop twice");
+ temp_date = parse_date_string(optarg);
+ timeinfo->date_stop = temp_date;
+ *flags |= IPT_DATE_STOP;
+ break;
default:
return 0;
}
return 1;
}
-/* Final check; must have specified --timestart --timestop --days. */
+/* Final check */
static void
final_check(unsigned int flags)
{
- if (flags != (IPT_TIME_START | IPT_TIME_STOP | IPT_TIME_DAYS))
- exit_error(PARAMETER_PROBLEM,
- "TIME match: You must specify `--timestart --timestop and --days'");
+ /* Nothing to do */
}
++nbdays;
}
}
+ printf(" ");
}
static void
*minutes = fulltime % 60;
}
+static void
+print_date(time_t date, char *command)
+{
+ struct tm *t;
+
+ /* If it's default value, don't print..*/
+ if (((date == 0) || (date == LONG_MAX)) && (command != NULL))
+ return;
+ t = localtime(&date);
+ if (command != NULL)
+ printf("%s %d:%d:%d:%d:%d:%d ", command, (t->tm_year + 1900), (t->tm_mon + 1),
+ t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+ else
+ printf("%d-%d-%d %d:%d:%d ", (t->tm_year + 1900), (t->tm_mon + 1),
+ t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+}
+
/* Prints out the matchinfo. */
static void
print(const struct ipt_ip *ip,
divide_time(time->time_start, &hour_start, &minute_start);
divide_time(time->time_stop, &hour_stop, &minute_stop);
- printf(" TIME from %d:%d to %d:%d on ",
- hour_start, minute_start,
- hour_stop, minute_stop);
- print_days(time->days_match);
- printf(" ");
+ printf("TIME ");
+ if (time->time_start != 0)
+ printf("from %d:%d ", hour_start, minute_start);
+ if (time->time_stop != 1439) /* 23*60+59 = 1439 */
+ printf("to %d:%d ", hour_stop, minute_stop);
+ printf("on ");
+ if (time->days_match == 127)
+ printf("all days ");
+ else
+ print_days(time->days_match);
+ if (time->date_start != 0)
+ {
+ printf("starting from ");
+ print_date(time->date_start, NULL);
+ }
+ if (time->date_stop != LONG_MAX)
+ {
+ printf("until date ");
+ print_date(time->date_stop, NULL);
+ }
}
/* Saves the data in parsable form to stdout. */
divide_time(time->time_start, &hour_start, &minute_start);
divide_time(time->time_stop, &hour_stop, &minute_stop);
- printf(" --timestart %.2d:%.2d --timestop %.2d:%.2d --days ",
- hour_start, minute_start,
- hour_stop, minute_stop);
- print_days(time->days_match);
- printf(" ");
+ if (time->time_start != 0)
+ printf("--timestart %.2d:%.2d ",
+ hour_start, minute_start);
+
+ if (time->time_stop != 1439) /* 23*60+59 = 1439 */
+ printf("--timestop %.2d:%.2d ",
+ hour_stop, minute_stop);
+
+ if (time->days_match != 127)
+ {
+ printf("--days ");
+ print_days(time->days_match);
+ printf(" ");
+ }
+ print_date(time->date_start, "--datestart");
+ print_date(time->date_stop, "--datestop");
}
+/* have to use offsetof() instead of IPT_ALIGN(), since kerneltime must not
+ * be compared when user deletes rule with '-D' */
static
-struct iptables_match timestruct
-= { NULL,
- "time",
- IPTABLES_VERSION,
- IPT_ALIGN(sizeof(struct ipt_time_info)),
- IPT_ALIGN(sizeof(struct ipt_time_info)),
- &help,
- &init,
- &parse,
- &final_check,
- &print,
- &save,
- opts
+struct iptables_match timestruct = {
+ .next = NULL,
+ .name = "time",
+ .version = IPTABLES_VERSION,
+ .size = IPT_ALIGN(sizeof(struct ipt_time_info)),
+ .userspacesize = offsetof(struct ipt_time_info, kerneltime),
+ .help = &help,
+ .init = &init,
+ .parse = &parse,
+ .final_check = &final_check,
+ .print = &print,
+ .save = &save,
+ .extra_opts = opts
};
void _init(void)