1 /* Shared library add-on to iptables to add TIME matching support. */
6 #include <stddef.h> /* for 'offsetof' */
10 #include <linux/netfilter_ipv4/ipt_time.h>
13 static int globaldays
;
15 /* Function which prints out usage message. */
21 " [ --timestart value ] [ --timestop value] [ --days listofdays ] [ --datestart value ] [ --datestop value ]\n"
22 " timestart value : HH:MM (default 00:00)\n"
23 " timestop value : HH:MM (default 23:59)\n"
24 " Note: daylight savings time changes are not tracked\n"
25 " listofdays value: a list of days to apply\n"
26 " from Mon,Tue,Wed,Thu,Fri,Sat,Sun\n"
27 " Coma speparated, no space, case sensitive.\n"
28 " Defaults to all days.\n"
29 " datestart value : YYYY[:MM[:DD[:hh[:mm[:ss]]]]]\n"
30 " If any of month, day, hour, minute or second is\n"
31 " not specified, then defaults to their smallest\n"
32 " 1900 <= YYYY < 2037\n"
38 " datestop value : YYYY[:MM[:DD[:hh[:mm[:ss]]]]]\n"
39 " If the whole option is ommited, default to never stop\n"
40 " If any of month, day, hour, minute or second is\n"
41 " not specified, then default to their smallest\n",
45 static struct option opts
[] = {
46 { "timestart", 1, 0, '1' },
47 { "timestop", 1, 0, '2' },
49 { "datestart", 1, 0, '4' },
50 { "datestop", 1, 0, '5' },
54 /* Initialize the match. */
56 init(struct ipt_entry_match
*m
, unsigned int *nfcache
)
58 struct ipt_time_info
*info
= (struct ipt_time_info
*)m
->data
;
60 /* By default, we match on everyday */
61 info
->days_match
= 127;
62 /* By default, we match on every hour:min of the day */
64 info
->time_stop
= 1439; /* (23*60+59 = 1439 */
65 /* By default, we don't have any date-begin or date-end boundaries */
67 info
->date_stop
= LONG_MAX
;
71 * param: part1, a pointer on a string 2 chars maximum long string, that will contain the hours.
72 * param: part2, a pointer on a string 2 chars maximum long string, that will contain the minutes.
73 * param: str_2_parse, the string to parse.
74 * return: 1 if ok, 0 if error.
77 split_time(char **part1
, char **part2
, const char *str_2_parse
)
79 unsigned short int i
,j
=0;
80 char *rpart1
= *part1
;
81 char *rpart2
= *part2
;
82 unsigned char found_column
= 0;
84 /* Check the length of the string */
85 if (strlen(str_2_parse
) > 5)
87 /* parse the first part until the ':' */
90 if (str_2_parse
[i
] == ':')
93 rpart1
[i
] = str_2_parse
[i
];
98 /* parse the second part */
99 for (; i
<strlen(str_2_parse
); i
++)
101 rpart2
[i
-j
] = str_2_parse
[i
];
103 /* if we are here, format should be ok. */
108 parse_number(char *str
, int num_min
, int num_max
, int *number
)
110 /* if the number starts with 0, replace it with a space else
111 string_to_number() will interpret it as octal !! */
112 if (strlen(str
) == 0)
115 if ((str
[0] == '0') && (str
[1] != '\0'))
118 return string_to_number(str
, num_min
, num_max
, number
);
122 parse_time_string(int *hour
, int *minute
, const char *time
)
126 hours
= (char *)malloc(3);
127 minutes
= (char *)malloc(3);
129 memset(minutes
, 0, 3);
131 if (split_time((char **)&hours
, (char **)&minutes
, time
) == 1)
135 if ((parse_number((char *)hours
, 0, 23, hour
) != -1) &&
136 (parse_number((char *)minutes
, 0, 59, minute
) != -1))
147 /* If we are here, there was a problem ..*/
148 exit_error(PARAMETER_PROBLEM
,
149 "invalid time `%s' specified, should be HH:MM format", time
);
152 /* return 1->ok, return 0->error */
154 parse_day(int *days
, int from
, int to
, const char *string
)
157 char *days_str
[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
158 unsigned short int days_of_week
[7] = {64, 32, 16, 8, 4, 2, 1};
161 dayread
= (char *)malloc(4);
163 if ((to
-from
) != 3) {
167 for (i
=from
; i
<to
; i
++)
168 dayread
[i
-from
] = string
[i
];
170 if (strcmp(dayread
, days_str
[i
]) == 0)
172 *days
|= days_of_week
[i
];
176 /* if we are here, we didn't read a valid day */
182 parse_days_string(int *days
, const char *daystring
)
186 char *err
= "invalid days `%s' specified, should be Sun,Mon,Tue... format";
188 len
= strlen(daystring
);
190 exit_error(PARAMETER_PROBLEM
, err
, daystring
);
193 if (parse_day(days
, i
, i
+3, daystring
) == 0)
194 exit_error(PARAMETER_PROBLEM
, err
, daystring
);
200 parse_date_field(const char *str_to_parse
, int str_to_parse_s
, int start_pos
,
201 char *dest
, int *next_pos
)
203 unsigned char found_value
= 0;
204 unsigned char found_column
= 0;
209 if ((i
+start_pos
) >= str_to_parse_s
) /* don't exit boundaries of the string.. */
211 if (str_to_parse
[i
+start_pos
] == ':')
216 dest
[i
] = str_to_parse
[i
+start_pos
];
219 if (found_value
== 0)
221 *next_pos
= i
+ start_pos
;
222 if (found_column
== 0)
228 split_date(char *year
, char *month
, char *day
,
229 char *hour
, char *minute
, char *second
,
230 const char *str_to_parse
)
233 unsigned char found_column
= 0;
234 int str_to_parse_s
= strlen(str_to_parse
);
236 /* Check the length of the string */
237 if ((str_to_parse_s
> 19) || /* YYYY:MM:DD:HH:MM:SS */
238 (str_to_parse_s
< 4)) /* YYYY*/
241 /* Clear the buffers */
246 memset(minute
, 0, 2);
247 memset(second
, 0, 2);
249 /* parse the year YYYY */
253 if (i
>= str_to_parse_s
)
255 if (str_to_parse
[i
] == ':')
261 year
[i
] = str_to_parse
[i
];
263 if (found_column
== 1)
266 /* parse the month if it exists */
267 if (! parse_date_field(str_to_parse
, str_to_parse_s
, i
, month
, &i
))
270 if (! parse_date_field(str_to_parse
, str_to_parse_s
, i
, day
, &i
))
273 if (! parse_date_field(str_to_parse
, str_to_parse_s
, i
, hour
, &i
))
276 if (! parse_date_field(str_to_parse
, str_to_parse_s
, i
, minute
, &i
))
279 parse_date_field(str_to_parse
, str_to_parse_s
, i
, second
, &i
);
281 /* if we are here, format should be ok. */
286 parse_date_string(const char *str_to_parse
)
301 memset(minute
, 0, 3);
302 memset(second
, 0, 3);
304 if (split_date(year
, month
, day
, hour
, minute
, second
, str_to_parse
) == 1)
306 memset((void *)&t
, 0, sizeof(struct tm
));
309 if (!((parse_number(year
, 1900, 2037, &(t
.tm_year
)) == -1) ||
310 (parse_number(month
, 1, 12, &(t
.tm_mon
)) == -1) ||
311 (parse_number(day
, 1, 31, &(t
.tm_mday
)) == -1) ||
312 (parse_number(hour
, 0, 9999, &(t
.tm_hour
)) == -1) ||
313 (parse_number(minute
, 0, 59, &(t
.tm_min
)) == -1) ||
314 (parse_number(second
, 0, 59, &(t
.tm_sec
)) == -1)))
318 temp_time
= mktime(&t
);
323 exit_error(PARAMETER_PROBLEM
,
324 "invalid date `%s' specified, should be YYYY[:MM[:DD[:hh[:mm[:ss]]]]] format", str_to_parse
);
327 #define IPT_TIME_START 0x01
328 #define IPT_TIME_STOP 0x02
329 #define IPT_TIME_DAYS 0x04
330 #define IPT_DATE_START 0x08
331 #define IPT_DATE_STOP 0x10
333 /* Function which parses command options; returns true if it
336 parse(int c
, char **argv
, int invert
, unsigned int *flags
,
337 const struct ipt_entry
*entry
,
338 unsigned int *nfcache
,
339 struct ipt_entry_match
**match
)
341 struct ipt_time_info
*timeinfo
= (struct ipt_time_info
*)(*match
)->data
;
350 exit_error(PARAMETER_PROBLEM
,
351 "unexpected '!' with --timestart");
352 if (*flags
& IPT_TIME_START
)
353 exit_error(PARAMETER_PROBLEM
,
354 "Can't specify --timestart twice");
355 parse_time_string(&hours
, &minutes
, optarg
);
356 timeinfo
->time_start
= (hours
* 60) + minutes
;
357 *flags
|= IPT_TIME_START
;
362 exit_error(PARAMETER_PROBLEM
,
363 "unexpected '!' with --timestop");
364 if (*flags
& IPT_TIME_STOP
)
365 exit_error(PARAMETER_PROBLEM
,
366 "Can't specify --timestop twice");
367 parse_time_string(&hours
, &minutes
, optarg
);
368 timeinfo
->time_stop
= (hours
* 60) + minutes
;
369 *flags
|= IPT_TIME_STOP
;
375 exit_error(PARAMETER_PROBLEM
,
376 "unexpected '!' with --days");
377 if (*flags
& IPT_TIME_DAYS
)
378 exit_error(PARAMETER_PROBLEM
,
379 "Can't specify --days twice");
380 parse_days_string(&globaldays
, optarg
);
381 timeinfo
->days_match
= globaldays
;
382 *flags
|= IPT_TIME_DAYS
;
388 exit_error(PARAMETER_PROBLEM
,
389 "unexpected '!' with --datestart");
390 if (*flags
& IPT_DATE_START
)
391 exit_error(PARAMETER_PROBLEM
,
392 "Can't specify --datestart twice");
393 temp_date
= parse_date_string(optarg
);
394 timeinfo
->date_start
= temp_date
;
395 *flags
|= IPT_DATE_START
;
401 exit_error(PARAMETER_PROBLEM
,
402 "unexpected '!' with --datestop");
403 if (*flags
& IPT_DATE_STOP
)
404 exit_error(PARAMETER_PROBLEM
,
405 "Can't specify --datestop twice");
406 temp_date
= parse_date_string(optarg
);
407 timeinfo
->date_stop
= temp_date
;
408 *flags
|= IPT_DATE_STOP
;
418 final_check(unsigned int flags
)
425 print_days(int daynum
)
427 char *days
[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
428 unsigned short int days_of_week
[7] = {64, 32, 16, 8, 4, 2, 1};
429 unsigned short int i
, nbdays
=0;
431 for (i
=0; i
<7; i
++) {
432 if ((days_of_week
[i
] & daynum
) == days_of_week
[i
])
435 printf(",%s", days
[i
]);
437 printf("%s", days
[i
]);
445 divide_time(int fulltime
, int *hours
, int *minutes
)
447 *hours
= fulltime
/ 60;
448 *minutes
= fulltime
% 60;
452 print_date(time_t date
, char *command
)
456 /* If it's default value, don't print..*/
457 if (((date
== 0) || (date
== LONG_MAX
)) && (command
!= NULL
))
459 t
= localtime(&date
);
461 printf("%s %d:%d:%d:%d:%d:%d ", command
, (t
->tm_year
+ 1900), (t
->tm_mon
+ 1),
462 t
->tm_mday
, t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
464 printf("%d-%d-%d %d:%d:%d ", (t
->tm_year
+ 1900), (t
->tm_mon
+ 1),
465 t
->tm_mday
, t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
468 /* Prints out the matchinfo. */
470 print(const struct ipt_ip
*ip
,
471 const struct ipt_entry_match
*match
,
474 struct ipt_time_info
*time
= ((struct ipt_time_info
*)match
->data
);
475 int hour_start
, hour_stop
, minute_start
, minute_stop
;
477 divide_time(time
->time_start
, &hour_start
, &minute_start
);
478 divide_time(time
->time_stop
, &hour_stop
, &minute_stop
);
480 if (time
->time_start
!= 0)
481 printf("from %d:%d ", hour_start
, minute_start
);
482 if (time
->time_stop
!= 1439) /* 23*60+59 = 1439 */
483 printf("to %d:%d ", hour_stop
, minute_stop
);
485 if (time
->days_match
== 127)
488 print_days(time
->days_match
);
489 if (time
->date_start
!= 0)
491 printf("starting from ");
492 print_date(time
->date_start
, NULL
);
494 if (time
->date_stop
!= LONG_MAX
)
496 printf("until date ");
497 print_date(time
->date_stop
, NULL
);
501 /* Saves the data in parsable form to stdout. */
503 save(const struct ipt_ip
*ip
, const struct ipt_entry_match
*match
)
505 struct ipt_time_info
*time
= ((struct ipt_time_info
*)match
->data
);
506 int hour_start
, hour_stop
, minute_start
, minute_stop
;
508 divide_time(time
->time_start
, &hour_start
, &minute_start
);
509 divide_time(time
->time_stop
, &hour_stop
, &minute_stop
);
510 if (time
->time_start
!= 0)
511 printf("--timestart %.2d:%.2d ",
512 hour_start
, minute_start
);
514 if (time
->time_stop
!= 1439) /* 23*60+59 = 1439 */
515 printf("--timestop %.2d:%.2d ",
516 hour_stop
, minute_stop
);
518 if (time
->days_match
!= 127)
521 print_days(time
->days_match
);
524 print_date(time
->date_start
, "--datestart");
525 print_date(time
->date_stop
, "--datestop");
528 /* have to use offsetof() instead of IPT_ALIGN(), since kerneltime must not
529 * be compared when user deletes rule with '-D' */
531 struct iptables_match timestruct
= {
534 .version
= IPTABLES_VERSION
,
535 .size
= IPT_ALIGN(sizeof(struct ipt_time_info
)),
536 .userspacesize
= offsetof(struct ipt_time_info
, kerneltime
),
540 .final_check
= &final_check
,
548 register_match(×truct
);