www.usr.com/support/gpl/USR9107_release.1.4.tar.gz
[bcm963xx.git] / userapps / opensource / ebtables / extensions / ebt_time.c
1 /*
2   Description: EBTables time extension module for userspace.
3   Authors:  Song Wang <songw@broadcom.com>, ported from netfilter/iptables
4             The following is the original disclaimer.
5
6  Shared library add-on to iptables to add TIME matching support. 
7 */
8 #include <stdio.h>
9 #include <netdb.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <getopt.h>
13 #include <errno.h>
14
15 #include "../include/ebtables_u.h"
16 #include <linux/netfilter_bridge/ebt_time.h>
17 #include <time.h>
18
19 static int globaldays;
20
21 /* Function which prints out usage message. */
22 static void
23 help(void)
24 {
25         printf(
26 "time options:\n"
27 " --timestart value --timestop value --days listofdays\n"
28 "          timestart value : HH:MM\n"
29 "          timestop  value : HH:MM\n"
30 "          listofdays value: a list of days to apply -> ie. Mon,Tue,Wed,Thu,Fri. Case sensitive\n");
31 }
32
33 static struct option opts[] = {
34         { "timestart", 1, 0, '1' },
35         { "timestop", 1, 0, '2' },
36         { "days", 1, 0, '3'},
37         {0}
38 };
39
40 /* Initialize the match. */
41 static void
42 init(struct ebt_entry_match *m)
43 {
44         globaldays = 0;
45 }
46
47 static int
48 string_to_number(const char *s, unsigned int min, unsigned int max,
49                  unsigned int *ret)
50 {
51         long number;
52         char *end;
53
54         /* Handle hex, octal, etc. */
55         errno = 0;
56         number = strtol(s, &end, 0);
57         if (*end == '\0' && end != s) {
58                 /* we parsed a number, let's see if we want this */
59                 if (errno != ERANGE && min <= number && number <= max) {
60                         *ret = number;
61                         return 0;
62                 }
63         }
64         return -1;
65 }
66
67 /**
68  * param: part1, a pointer on a string 2 chars maximum long string, that will contain the hours.
69  * param: part2, a pointer on a string 2 chars maximum long string, that will contain the minutes.
70  * param: str_2_parse, the string to parse.
71  * return: 1 if ok, 0 if error.
72  */
73 static int
74 split_time(char **part1, char **part2, const char *str_2_parse)
75 {
76         unsigned short int i,j=0;
77         char *rpart1 = *part1;
78         char *rpart2 = *part2;
79         unsigned char found_column = 0;
80
81         /* Check the length of the string */
82         if (strlen(str_2_parse) > 5)
83                 return 0;
84         /* parse the first part until the ':' */
85         for (i=0; i<2; i++)
86         {
87                 if (str_2_parse[i] == ':')
88                         found_column = 1;
89                 else
90                         rpart1[i] = str_2_parse[i];
91         }
92         if (!found_column)
93                 i++;
94         j=i;
95         /* parse the second part */
96         for (; i<strlen(str_2_parse); i++)
97         {
98                 rpart2[i-j] = str_2_parse[i];
99         }
100         /* if we are here, format should be ok. */
101         return 1;
102 }
103
104 static void
105 parse_time_string(unsigned int *hour, unsigned int *minute, const char *time)
106 {
107         char *hours;
108         char *minutes;
109
110         hours = (char *)malloc(3);
111         minutes = (char *)malloc(3);
112         bzero((void *)hours, 3);
113         bzero((void *)minutes, 3);
114
115         if (split_time(&hours, &minutes, time) == 1)
116         {
117                 /* if the number starts with 0, replace it with a space else
118                    this string_to_number will interpret it as octal !! */
119                 if ((hours[0] == '0') && (hours[1] != '\0'))
120                         hours[0] = ' ';
121                 if ((minutes[0] == '0') && (minutes[1] != '\0'))
122                         minutes[0] = ' ';
123
124                 if((string_to_number(hours, 0, 23, hour) == -1) ||
125                         (string_to_number(minutes, 0, 59, minute) == -1)) {
126                         *hour = *minute = (-1);
127                 }
128         }
129         if ((*hour != (-1)) && (*minute != (-1))) {
130                 free(hours);
131                 free(minutes);
132                 return;
133         }
134
135         /* If we are here, there was a problem ..*/
136         print_error("invalid time %s specified, should be HH:MM format", time);
137 }
138
139 /* return 1->ok, return 0->error */
140 static int
141 parse_day(int *days, int from, int to, const char *string)
142 {
143         char *dayread;
144         char *days_str[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
145         unsigned short int days_of_week[7] = {64, 32, 16, 8, 4, 2, 1};
146         unsigned int i;
147
148         dayread = (char *)malloc(4);
149         bzero(dayread, 4);
150         if ((to-from) != 3) {
151                 free(dayread);
152                 return 0;
153         }
154         for (i=from; i<to; i++)
155                 dayread[i-from] = string[i];
156         for (i=0; i<7; i++)
157                 if (strcmp(dayread, days_str[i]) == 0)
158                 {
159                         *days |= days_of_week[i];
160                         free(dayread);
161                         return 1;
162                 }
163         /* if we are here, we didn't read a valid day */
164         free(dayread);
165         return 0;
166 }
167
168 static void
169 parse_days_string(int *days, const char *daystring)
170 {
171         int len;
172         int i=0;
173         //char *err = "invalid days specified, should be Sun,Mon,Tue... format";
174
175         len = strlen(daystring);
176         if (len < 3)
177                 print_error("invalid days specified, should be Sun,Mon,Tue... format"); 
178         while(i<len)
179         {
180                 if (parse_day(days, i, i+3, daystring) == 0)
181                         print_error("invalid days specified, should be Sun,Mon,Tue... format");
182                 i += 4;
183         }
184 }
185
186 #define EBT_TIME_START 0x01
187 #define EBT_TIME_STOP  0x02
188 #define EBT_TIME_DAYS  0x04
189
190
191 /* Function which parses command options; returns true if it
192    ate an option */
193 static int
194 parse(int c, char **argv, int argc,
195       const struct ebt_u_entry *entry,
196       unsigned int *flags, struct ebt_entry_match **match)
197 {
198         struct ebt_time_info *timeinfo = (struct ebt_time_info *)(*match)->data;
199         int hours, minutes;
200
201         switch (c) /* c is the return value of getopt_long */
202         {
203                 /* timestart */
204         case '1':
205                 if (*flags & EBT_TIME_START)
206                         print_error("Can't specify --timestart twice");
207                 parse_time_string(&hours, &minutes, optarg);
208                 timeinfo->time_start = (hours * 60) + minutes;
209                 *flags |= EBT_TIME_START;
210                 break;
211                 /* timestop */
212         case '2':
213                 if (*flags & EBT_TIME_STOP)
214                         print_error("Can't specify --timestop twice");
215                 parse_time_string(&hours, &minutes, optarg);
216                 timeinfo->time_stop = (hours * 60) + minutes;
217                 *flags |= EBT_TIME_STOP;
218                 break;
219
220                 /* days */
221         case '3':
222                 if (*flags & EBT_TIME_DAYS)
223                         print_error("Can't specify --days twice");
224                 parse_days_string(&globaldays, optarg);
225                 timeinfo->days_match = globaldays;
226                 *flags |= EBT_TIME_DAYS;
227                 break;
228         default:
229                 return 0;
230         }
231         /* default value if not specified */
232         if (!(*flags & EBT_TIME_START))
233                 timeinfo->time_start = 0;
234         if (!(*flags & EBT_TIME_STOP))
235                 timeinfo->time_stop = 1439; /* 23*60+59 = 1439*/
236         if (!(*flags & EBT_TIME_DAYS))
237                 timeinfo->days_match = 0;
238
239         return 1;
240 }
241
242 /* Final check; must have specified --timestart --timestop --days. */
243 static void
244 final_check(const struct ebt_u_entry *entry,
245    const struct ebt_entry_match *match, const char *name,
246    unsigned int hookmask, unsigned int time)
247 {
248         struct ebt_time_info *timeinfo = (struct ebt_time_info *)match->data;
249
250         /*
251         printf("start=%d,stop=%d,days=%d\n",
252                 timeinfo->time_start,timeinfo->time_stop,timeinfo->days_match);
253         */
254         if (timeinfo->time_stop < timeinfo->time_start)
255                 print_error("stop time can't be smaller than start time");
256 }
257
258
259 static void
260 print_days(int daynum)
261 {
262         char *days[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
263         unsigned short int days_of_week[7] = {64, 32, 16, 8, 4, 2, 1};
264         unsigned short int i, nbdays=0;
265
266         for (i=0; i<7; i++) {
267                 if ((days_of_week[i] & daynum) == days_of_week[i])
268                 {
269                         if (nbdays>0)
270                                 printf(",%s", days[i]);
271                         else
272                                 printf("%s", days[i]);
273                         ++nbdays;
274                 }
275         }
276 }
277
278 static void
279 divide_time(int fulltime, int *hours, int *minutes)
280 {
281         *hours = fulltime / 60;
282         *minutes = fulltime % 60;
283 }
284
285 /* Prints out the matchinfo. */
286 static void
287 print(const struct ebt_u_entry *entry,
288       const struct ebt_entry_match *match)
289 {
290         struct ebt_time_info *time = ((struct ebt_time_info *)match->data);
291         int hour_start, hour_stop, minute_start, minute_stop;
292
293         divide_time(time->time_start, &hour_start, &minute_start);
294         divide_time(time->time_stop, &hour_stop, &minute_stop);
295         printf(" TIME from %d:%d to %d:%d on ",
296                hour_start, minute_start,
297                hour_stop, minute_stop);
298         print_days(time->days_match);
299         printf(" ");
300 }
301
302 #if 0
303 /* Saves the data in parsable form to stdout. */
304 static void
305 save(const struct ipt_ip *ip, const struct ebt_entry_match *match)
306 {
307         struct ebt_time_info *time = ((struct ebt_time_info *)match->data);
308         int hour_start, hour_stop, minute_start, minute_stop;
309
310         divide_time(time->time_start, &hour_start, &minute_start);
311         divide_time(time->time_stop, &hour_stop, &minute_stop);
312         printf(" --timestart %.2d:%.2d --timestop %.2d:%.2d --days ",
313                hour_start, minute_start,
314                hour_stop, minute_stop);
315         print_days(time->days_match);
316         printf(" ");
317 }
318 #endif
319
320 static int 
321 compare(const struct ebt_entry_match *m1, const struct ebt_entry_match *m2)
322 {
323         struct ebt_time_info *timeinfo1 = (struct ebt_time_info *)m1->data;
324         struct ebt_time_info *timeinfo2 = (struct ebt_time_info *)m2->data;
325
326         if (timeinfo1->days_match != timeinfo2->days_match)
327                 return 0;
328         if (timeinfo1->time_start != timeinfo2->time_start)
329                 return 0;
330         if (timeinfo1->time_stop != timeinfo2->time_stop)
331                 return 0;
332         return 1;
333 }
334
335 static
336 struct ebt_u_match time_match
337 = { "time",
338     sizeof(struct ebt_time_info),
339     help,
340     init,
341     parse,
342     final_check,
343     print,
344     compare,
345     opts
346 };
347
348 static void _init(void) __attribute((constructor));
349 void _init(void)
350 {
351         register_match(&time_match);
352 }