
jengelh at computergmbh
Aug 20, 2007, 12:20 PM
Post #1 of 1
(466 views)
Permalink
|
|
xt_time 20070820 (iptables)
|
|
iptables part. --- extensions/.time-testx | 2 extensions/libxt_time.man | 16 + extensions/libxt_time.c | 497 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 515 insertions(+) Index: iptables/extensions/.time-testx =================================================================== --- /dev/null +++ iptables/extensions/.time-testx @@ -0,0 +1,2 @@ +#!/bin/sh +[ -f "$KERNEL_DIR/include/linux/netfilter/xt_time.h" ] && echo time Index: iptables/extensions/libipt_time.man =================================================================== --- /dev/null +++ iptables/extensions/libxt_time.man @@ -0,0 +1,16 @@ +This matches if the packet arrival time/date is within a given range. All options are facultative. +.TP +.BI " --timestart " "value" +Match only if it is after `value' (Inclusive, format: HH:MM ; default 00:00). +.TP +.BI "--timestop " "value" +Match only if it is before `value' (Inclusive, format: HH:MM ; default 23:59). +.TP +.BI "--days " "listofdays" +Match only if today is one of the given days. (format: Mon,Tue,Wed,Thu,Fri,Sat,Sun ; default everyday) +.TP +.BI "--datestart " "date" +Match only if it is after `date' (Inclusive, format: YYYY[:MM[:DD[:hh[:mm[:ss]]]]] ; h,m,s start from 0 ; default to 1970) +.TP +.BI "--datestop " "date" +Match only if it is before `date' (Inclusive, format: YYYY[:MM[:DD[:hh[:mm[:ss]]]]] ; h,m,s start from 0 ; default to 2037) Index: iptables/extensions/libxt_time.c =================================================================== --- /dev/null +++ iptables/extensions/libxt_time.c @@ -0,0 +1,497 @@ +/* Shared library add-on to iptables to add TIME matching support. */ +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <stdlib.h> +#include <stddef.h> /* for 'offsetof' */ +#include <getopt.h> + +#include <xtables.h> +#include <linux/netfilter/xt_time.h> +#include <time.h> + +static int globaldays; + +/* Function which prints out usage message. */ +static void time_help(void) +{ + printf( +"TIME v%s options:\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); +} + +static const struct option time_opts[] = { + {"timestart", 1, NULL, '1'}, + {"timestop", 1, NULL, '2'}, + {"days", 1, NULL, '3'}, + {"datestart", 1, NULL, '4'}, + {"datestop", 1, NULL, '5'}, + {NULL}, +}; + +/* Initialize the match. */ +static void time_init(struct xt_entry_match *m, unsigned int *nfcache) +{ + struct xt_time_info *info = (void *)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 = 24 * 60 - 1; /* 23:59 */ + + /* By default, we do not have any date-begin or date-end boundaries */ + info->date_start = 0; + info->date_stop = LONG_MAX; +} + +/* + * @param: part1, a pointer on a string 2 chars maximum long string, + * that will contain the hours. + * @param: part2, a pointer on a string 2 chars maximum long string, + * that will contain the minutes. + * @param: str_2_parse, the string to parse. + * + * returns 1 if ok, 0 if error. + */ +static int split_time(char *rpart1, char *rpart2, const char *str_2_parse) +{ + unsigned int i, j, found_column = 0; + + /* Check the length of the string */ + if (strlen(str_2_parse) > 5) + return 0; + + /* parse the first part until the ':' */ + for (i = 0; i < 2; ++i) { + if (str_2_parse[i] == ':') + found_column = 1; + else + rpart1[i] = str_2_parse[i]; + } + if (!found_column) + ++i; + + j = i; + + /* parse the second part */ + for (; i < strlen(str_2_parse); ++i) + rpart2[i-j] = str_2_parse[i]; + + /* if we are here, format should be ok. */ + return 1; +} + +static int parse_number(char *str, unsigned int num_min, unsigned int num_max, + unsigned 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 inline int parse_inumber(char *str, unsigned int num_min, + unsigned int num_max, int *number) +{ + return parse_number(str, num_min, num_max, (unsigned int *)number); +} + +static void parse_time_string(unsigned int *hour, unsigned int *minute, + const char *time) +{ + char hours[3] = {}; + char minutes[3] = {}; + + if (split_time(hours, minutes, time) == 1) { + *hour = 0; + *minute = 0; + if (parse_number(hours, 0, 23, hour) != -1 && + parse_number(minutes, 0, 59, minute) != -1) + return; + } + + /* If we are here, there was a problem ..*/ + exit_error(PARAMETER_PROBLEM, "invalid time \"%s\" specified, " + "should be HH:MM format", time); +} + +static const char *const days_str[] = + {NULL, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; +static const unsigned char days_of_week[] = + {0, XT_TIME_MONDAY, XT_TIME_TUESDAY, XT_TIME_WEDNESDAY, + XT_TIME_THURSDAY, XT_TIME_FRIDAY, XT_TIME_SATURDAY, + XT_TIME_SUNDAY}; + +/* return 1->ok, return 0->error */ +static int parse_day(unsigned int *days, unsigned int from, unsigned int to, + const char *string) +{ + char dayread[4] = {}; + unsigned int i; + + if (to - from != 3) { + free(dayread); + return 0; + } + for (i = from; i < to; ++i) + dayread[i - from] = string[i]; + for (i = 1; i <= 7; ++i) + if (strcmp(dayread, days_str[i]) == 0) { + *days |= days_of_week[i]; + return 1; + } + return 0; +} + +static void parse_days_string(unsigned int *days, const char *daystring) +{ + static const char *const err = "invalid days \"%s\" specified, should be Sun,Mon,Tue... format"; + unsigned int i = 0; + unsigned int len; + + len = strlen(daystring); + if (len < 3) + exit_error(PARAMETER_PROBLEM, err, daystring); + for (i = 0; i < len; i += 4) { + if (parse_day(days, i, i + 3, daystring) == 0) + exit_error(PARAMETER_PROBLEM, err, daystring); + i += 4; + } +} + +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] = {}, month[3] = {}, day[3] = {}, + hour[3] = {}, minute[3] = {}, second[3] = {}; + struct tm t; + time_t temp_time; + + if (split_date(year, month, day, hour, minute, + second, str_to_parse) == 1) { + memset(&t, 0, sizeof(struct tm)); + t.tm_isdst = -1; + t.tm_mday = 1; + if (!((parse_inumber(year, 1900, 2037, &t.tm_year) == -1) || + (parse_inumber(month, 1, 12, &t.tm_mon) == -1) || + (parse_inumber(day, 1, 31, &t.tm_mday) == -1) || + (parse_inumber(hour, 0, 9999, &t.tm_hour) == -1) || + (parse_inumber(minute, 0, 59, &t.tm_min) == -1) || + (parse_inumber(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); +} + +enum { + XT_TIME_START = 1 << 0, + XT_TIME_STOP = 1 << 1, + XT_TIME_DAYS = 1 << 2, + XT_DATE_START = 1 << 3, + XT_DATE_STOP = 1 << 4, +}; + +/* Function which parses command options; returns true if it + ate an option */ +static int time_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, unsigned int *nfcache, + struct xt_entry_match **match) +{ + struct xt_time_info *timeinfo = (void *)(*match)->data; + unsigned int hours, minutes; + time_t temp_date; + + switch (c) { + case '1': /* timestart */ + if (invert) + exit_error(PARAMETER_PROBLEM, + "unexpected '!' with --timestart"); + if (*flags & XT_TIME_START) + exit_error(PARAMETER_PROBLEM, + "Can't specify --timestart twice"); + parse_time_string(&hours, &minutes, optarg); + timeinfo->time_start = (hours * 60) + minutes; + *flags |= XT_TIME_START; + break; + case '2': /* timestop */ + if (invert) + exit_error(PARAMETER_PROBLEM, + "unexpected '!' with --timestop"); + if (*flags & XT_TIME_STOP) + exit_error(PARAMETER_PROBLEM, + "Can't specify --timestop twice"); + parse_time_string(&hours, &minutes, optarg); + timeinfo->time_stop = (hours * 60) + minutes; + *flags |= XT_TIME_STOP; + break; + case '3': /* days */ + if (invert) + exit_error(PARAMETER_PROBLEM, + "unexpected '!' with --days"); + if (*flags & XT_TIME_DAYS) + exit_error(PARAMETER_PROBLEM, + "Can't specify --days twice"); + parse_days_string(&globaldays, optarg); + timeinfo->days_match = globaldays; + *flags |= XT_TIME_DAYS; + break; + case '4': /* datestart */ + if (invert) + exit_error(PARAMETER_PROBLEM, + "unexpected '!' with --datestart"); + if (*flags & XT_DATE_START) + exit_error(PARAMETER_PROBLEM, + "Can't specify --datestart twice"); + temp_date = parse_date_string(optarg); + timeinfo->date_start = temp_date; + *flags |= XT_DATE_START; + break; + case '5': /* datestop */ + if (invert) + exit_error(PARAMETER_PROBLEM, + "unexpected '!' with --datestop"); + if (*flags & XT_DATE_STOP) + exit_error(PARAMETER_PROBLEM, + "Can't specify --datestop twice"); + temp_date = parse_date_string(optarg); + timeinfo->date_stop = temp_date; + *flags |= XT_DATE_STOP; + break; + default: + return 0; + } + return 1; +} + +static void time_check(unsigned int flags) +{ +} + +static void print_days(int daynum) +{ + unsigned int i, nbdays = 0; + + for (i = 1; i <= 7; ++i) { + if (daynum & days_of_week[i]) { + if (nbdays > 0) + printf(",%s", days_str[i]); + else + printf("%s", days_str[i]); + ++nbdays; + } + } + printf(" "); +} + +static void divide_time(unsigned int fulltime, unsigned int *hours, + unsigned int *minutes) +{ + *hours = fulltime / 60; + *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 time_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + struct xt_time_info *time = (void *)match->data; + unsigned int hour_start, hour_stop, minute_start, minute_stop; + + divide_time(time->time_start, &hour_start, &minute_start); + divide_time(time->time_stop, &hour_stop, &minute_stop); + printf("TIME "); + + if (time->time_start != 0) + printf("from %02u:%02u ", hour_start, minute_start); + if (time->time_stop != 24 * 60 - 1) + printf("to %02u:%02u ", 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. */ +static void time_save(const void *ip, const struct xt_entry_match *match) +{ + struct xt_time_info *time = (void *)match->data; + unsigned int hour_start, hour_stop, minute_start, minute_stop; + + divide_time(time->time_start, &hour_start, &minute_start); + divide_time(time->time_stop, &hour_stop, &minute_stop); + + if (time->time_start != 0) + printf("--timestart %02u:%02u ", + hour_start, minute_start); + if (time->time_stop != 24 * 60 - 1) + printf("--timestop %02u:%02u ", + 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"); +} + +static struct xtables_match time_reg = { + .name = "time", + .family = AF_INET, + .version = IPTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_time_info)), + .userspacesize = offsetof(struct xt_time_info, kerneltime), + .help = time_help, + .init = time_init, + .parse = time_parse, + .final_check = time_check, + .print = time_print, + .save = time_save, + .extra_opts = time_opts, +}; + +void _init(void) +{ + xtables_register_match(&time_reg); +}
|