Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / iptables / extensions / libipt_time.c
blobdcf2dc679d7e4e82e5eb6c8353a056a7418732a5
1 /* Shared library add-on to iptables to add TIME matching support. */
2 #include <stdio.h>
3 #include <netdb.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <stddef.h> /* for 'offsetof' */
7 #include <getopt.h>
9 #include <iptables.h>
10 #include <linux/netfilter_ipv4/ipt_time.h>
11 #include <time.h>
13 static int globaldays;
15 /* Function which prints out usage message. */
16 static void
17 help(void)
19 printf(
20 "TIME v%s options:\n"
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"
33 " 1 <= MM <= 12\n"
34 " 1 <= DD <= 31\n"
35 " 0 <= hh <= 23\n"
36 " 0 <= mm <= 59\n"
37 " 0 <= ss <= 59\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",
42 IPTABLES_VERSION);
45 static struct option opts[] = {
46 { "timestart", 1, 0, '1' },
47 { "timestop", 1, 0, '2' },
48 { "days", 1, 0, '3'},
49 { "datestart", 1, 0, '4' },
50 { "datestop", 1, 0, '5' },
51 {0}
54 /* Initialize the match. */
55 static void
56 init(struct ipt_entry_match *m, unsigned int *nfcache)
58 struct ipt_time_info *info = (struct ipt_time_info *)m->data;
59 globaldays = 0;
60 /* By default, we match on everyday */
61 info->days_match = 127;
62 /* By default, we match on every hour:min of the day */
63 info->time_start = 0;
64 info->time_stop = 1439; /* (23*60+59 = 1439 */
65 /* By default, we don't have any date-begin or date-end boundaries */
66 info->date_start = 0;
67 info->date_stop = LONG_MAX;
70 /**
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.
76 static int
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)
86 return 0;
87 /* parse the first part until the ':' */
88 for (i=0; i<2; i++)
90 if (str_2_parse[i] == ':')
91 found_column = 1;
92 else
93 rpart1[i] = str_2_parse[i];
95 if (!found_column)
96 i++;
97 j=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. */
104 return 1;
107 static int
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)
113 return 0;
115 if ((str[0] == '0') && (str[1] != '\0'))
116 str[0] = ' ';
118 return string_to_number(str, num_min, num_max, number);
121 static void
122 parse_time_string(int *hour, int *minute, const char *time)
124 char *hours;
125 char *minutes;
126 hours = (char *)malloc(3);
127 minutes = (char *)malloc(3);
128 memset(hours, 0, 3);
129 memset(minutes, 0, 3);
131 if (split_time((char **)&hours, (char **)&minutes, time) == 1)
133 *hour = 0;
134 *minute = 0;
135 if ((parse_number((char *)hours, 0, 23, hour) != -1) &&
136 (parse_number((char *)minutes, 0, 59, minute) != -1))
138 free(hours);
139 free(minutes);
140 return;
144 free(hours);
145 free(minutes);
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 */
153 static int
154 parse_day(int *days, int from, int to, const char *string)
156 char *dayread;
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};
159 unsigned int i;
161 dayread = (char *)malloc(4);
162 bzero(dayread, 4);
163 if ((to-from) != 3) {
164 free(dayread);
165 return 0;
167 for (i=from; i<to; i++)
168 dayread[i-from] = string[i];
169 for (i=0; i<7; i++)
170 if (strcmp(dayread, days_str[i]) == 0)
172 *days |= days_of_week[i];
173 free(dayread);
174 return 1;
176 /* if we are here, we didn't read a valid day */
177 free(dayread);
178 return 0;
181 static void
182 parse_days_string(int *days, const char *daystring)
184 int len;
185 int i=0;
186 char *err = "invalid days `%s' specified, should be Sun,Mon,Tue... format";
188 len = strlen(daystring);
189 if (len < 3)
190 exit_error(PARAMETER_PROBLEM, err, daystring);
191 while(i<len)
193 if (parse_day(days, i, i+3, daystring) == 0)
194 exit_error(PARAMETER_PROBLEM, err, daystring);
195 i += 4;
199 static int
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;
205 int i;
207 for (i=0; i<2; i++)
209 if ((i+start_pos) >= str_to_parse_s) /* don't exit boundaries of the string.. */
210 break;
211 if (str_to_parse[i+start_pos] == ':')
212 found_column = 1;
213 else
215 found_value = 1;
216 dest[i] = str_to_parse[i+start_pos];
219 if (found_value == 0)
220 return 0;
221 *next_pos = i + start_pos;
222 if (found_column == 0)
223 ++(*next_pos);
224 return 1;
227 static int
228 split_date(char *year, char *month, char *day,
229 char *hour, char *minute, char *second,
230 const char *str_to_parse)
232 int i;
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*/
239 return 0;
241 /* Clear the buffers */
242 memset(year, 0, 4);
243 memset(month, 0, 2);
244 memset(day, 0, 2);
245 memset(hour, 0, 2);
246 memset(minute, 0, 2);
247 memset(second, 0, 2);
249 /* parse the year YYYY */
250 found_column = 0;
251 for (i=0; i<5; i++)
253 if (i >= str_to_parse_s)
254 break;
255 if (str_to_parse[i] == ':')
257 found_column = 1;
258 break;
260 else
261 year[i] = str_to_parse[i];
263 if (found_column == 1)
264 ++i;
266 /* parse the month if it exists */
267 if (! parse_date_field(str_to_parse, str_to_parse_s, i, month, &i))
268 return 1;
270 if (! parse_date_field(str_to_parse, str_to_parse_s, i, day, &i))
271 return 1;
273 if (! parse_date_field(str_to_parse, str_to_parse_s, i, hour, &i))
274 return 1;
276 if (! parse_date_field(str_to_parse, str_to_parse_s, i, minute, &i))
277 return 1;
279 parse_date_field(str_to_parse, str_to_parse_s, i, second, &i);
281 /* if we are here, format should be ok. */
282 return 1;
285 static time_t
286 parse_date_string(const char *str_to_parse)
288 char year[5];
289 char month[3];
290 char day[3];
291 char hour[3];
292 char minute[3];
293 char second[3];
294 struct tm t;
295 time_t temp_time;
297 memset(year, 0, 5);
298 memset(month, 0, 3);
299 memset(day, 0, 3);
300 memset(hour, 0, 3);
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));
307 t.tm_isdst = -1;
308 t.tm_mday = 1;
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)))
316 t.tm_year -= 1900;
317 --(t.tm_mon);
318 temp_time = mktime(&t);
319 if (temp_time != -1)
320 return temp_time;
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
334 ate an option */
335 static int
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;
342 int hours, minutes;
343 time_t temp_date;
345 switch (c)
347 /* timestart */
348 case '1':
349 if (invert)
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;
358 break;
359 /* timestop */
360 case '2':
361 if (invert)
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;
370 break;
372 /* days */
373 case '3':
374 if (invert)
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;
383 break;
385 /* datestart */
386 case '4':
387 if (invert)
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;
396 break;
398 /* datestop*/
399 case '5':
400 if (invert)
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;
409 break;
410 default:
411 return 0;
413 return 1;
416 /* Final check */
417 static void
418 final_check(unsigned int flags)
420 /* Nothing to do */
424 static void
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])
434 if (nbdays>0)
435 printf(",%s", days[i]);
436 else
437 printf("%s", days[i]);
438 ++nbdays;
441 printf(" ");
444 static void
445 divide_time(int fulltime, int *hours, int *minutes)
447 *hours = fulltime / 60;
448 *minutes = fulltime % 60;
451 static void
452 print_date(time_t date, char *command)
454 struct tm *t;
456 /* If it's default value, don't print..*/
457 if (((date == 0) || (date == LONG_MAX)) && (command != NULL))
458 return;
459 t = localtime(&date);
460 if (command != NULL)
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);
463 else
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. */
469 static void
470 print(const struct ipt_ip *ip,
471 const struct ipt_entry_match *match,
472 int numeric)
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);
479 printf("TIME ");
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);
484 printf("on ");
485 if (time->days_match == 127)
486 printf("all days ");
487 else
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. */
502 static void
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)
520 printf("--days ");
521 print_days(time->days_match);
522 printf(" ");
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' */
530 static
531 struct iptables_match timestruct = {
532 .next = NULL,
533 .name = "time",
534 .version = IPTABLES_VERSION,
535 .size = IPT_ALIGN(sizeof(struct ipt_time_info)),
536 .userspacesize = offsetof(struct ipt_time_info, kerneltime),
537 .help = &help,
538 .init = &init,
539 .parse = &parse,
540 .final_check = &final_check,
541 .print = &print,
542 .save = &save,
543 .extra_opts = opts
546 void _init(void)
548 register_match(&timestruct);