blob: 909ca81df7da3b75b2096ec7c18b8be1e1e8ce74 [file] [log] [blame]
Harald Welte5ea4bcb2001-03-25 19:25:41 +00001/* 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 <getopt.h>
7
8#include <iptables.h>
9#include <linux/netfilter_ipv4/ipt_time.h>
10#include <time.h>
11
Fabrice MARIE358a33e2001-10-02 15:44:02 +000012static int globaldays;
13
Harald Welte5ea4bcb2001-03-25 19:25:41 +000014/* Function which prints out usage message. */
15static void
16help(void)
17{
18 printf(
19"TIME v%s options:\n"
20" --timestart value --timestop value --days listofdays\n"
21" timestart value : HH:MM\n"
22" timestop value : HH:MM\n"
23" listofdays value: a list of days to apply -> ie. Mon,Tue,Wed,Thu,Fri. Case sensitive\n",
Harald Welte80fe35d2002-05-29 13:08:15 +000024IPTABLES_VERSION);
Harald Welte5ea4bcb2001-03-25 19:25:41 +000025}
26
27static struct option opts[] = {
28 { "timestart", 1, 0, '1' },
29 { "timestop", 1, 0, '2' },
30 { "days", 1, 0, '3'},
31 {0}
32};
33
34/* Initialize the match. */
35static void
36init(struct ipt_entry_match *m, unsigned int *nfcache)
37{
38 /* caching not yet implemented */
39 *nfcache |= NFC_UNKNOWN;
Fabrice MARIE358a33e2001-10-02 15:44:02 +000040 globaldays = 0;
Harald Welte5ea4bcb2001-03-25 19:25:41 +000041}
42
Harald Welte5ea4bcb2001-03-25 19:25:41 +000043/**
44 * param: part1, a pointer on a string 2 chars maximum long string, that will contain the hours.
45 * param: part2, a pointer on a string 2 chars maximum long string, that will contain the minutes.
46 * param: str_2_parse, the string to parse.
47 * return: 1 if ok, 0 if error.
48 */
49static int
50split_time(char **part1, char **part2, const char *str_2_parse)
51{
Fabrice MARIEd7e251f2001-04-27 08:39:00 +000052 unsigned short int i,j=0;
Harald Welte5ea4bcb2001-03-25 19:25:41 +000053 char *rpart1 = *part1;
54 char *rpart2 = *part2;
Fabrice MARIEd7e251f2001-04-27 08:39:00 +000055 unsigned char found_column = 0;
Harald Welte5ea4bcb2001-03-25 19:25:41 +000056
57 /* Check the length of the string */
58 if (strlen(str_2_parse) > 5)
59 return 0;
60 /* parse the first part until the ':' */
61 for (i=0; i<2; i++)
62 {
Fabrice MARIEd7e251f2001-04-27 08:39:00 +000063 if (str_2_parse[i] == ':')
64 found_column = 1;
65 else
Harald Welte5ea4bcb2001-03-25 19:25:41 +000066 rpart1[i] = str_2_parse[i];
Harald Welte5ea4bcb2001-03-25 19:25:41 +000067 }
Fabrice MARIEd7e251f2001-04-27 08:39:00 +000068 if (!found_column)
69 i++;
70 j=i;
Harald Welte5ea4bcb2001-03-25 19:25:41 +000071 /* parse the second part */
Fabrice MARIEd7e251f2001-04-27 08:39:00 +000072 for (; i<strlen(str_2_parse); i++)
Harald Welte5ea4bcb2001-03-25 19:25:41 +000073 {
74 rpart2[i-j] = str_2_parse[i];
75 }
76 /* if we are here, format should be ok. */
77 return 1;
78}
79
80static void
Harald Welteb4719762001-07-23 02:14:22 +000081parse_time_string(unsigned int *hour, unsigned int *minute, const char *time)
Harald Welte5ea4bcb2001-03-25 19:25:41 +000082{
83 char *hours;
84 char *minutes;
85
86 hours = (char *)malloc(3);
87 minutes = (char *)malloc(3);
88 bzero((void *)hours, 3);
89 bzero((void *)minutes, 3);
90
91 if (split_time(&hours, &minutes, time) == 1)
92 {
Fabrice MARIEd7e251f2001-04-27 08:39:00 +000093 /* if the number starts with 0, replace it with a space else
94 this string_to_number will interpret it as octal !! */
Fabrice MARIE358a33e2001-10-02 15:44:02 +000095 if ((hours[0] == '0') && (hours[1] != '\0'))
Fabrice MARIEd7e251f2001-04-27 08:39:00 +000096 hours[0] = ' ';
Fabrice MARIE358a33e2001-10-02 15:44:02 +000097 if ((minutes[0] == '0') && (minutes[1] != '\0'))
Fabrice MARIEd7e251f2001-04-27 08:39:00 +000098 minutes[0] = ' ';
Harald Welteb4719762001-07-23 02:14:22 +000099
Marc Boucher459357f2001-09-08 02:16:51 +0000100 if((string_to_number(hours, 0, 23, hour) == -1) ||
101 (string_to_number(minutes, 0, 59, minute) == -1)) {
102 *hour = *minute = (-1);
103 }
Harald Welte5ea4bcb2001-03-25 19:25:41 +0000104 }
105 if ((*hour != (-1)) && (*minute != (-1))) {
106 free(hours);
107 free(minutes);
108 return;
109 }
110
111 /* If we are here, there was a problem ..*/
112 exit_error(PARAMETER_PROBLEM,
113 "invalid time `%s' specified, should be HH:MM format", time);
114}
115
116/* return 1->ok, return 0->error */
117static int
118parse_day(int *days, int from, int to, const char *string)
119{
120 char *dayread;
121 char *days_str[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
122 unsigned short int days_of_week[7] = {64, 32, 16, 8, 4, 2, 1};
123 unsigned int i;
124
125 dayread = (char *)malloc(4);
126 bzero(dayread, 4);
127 if ((to-from) != 3) {
128 free(dayread);
129 return 0;
130 }
131 for (i=from; i<to; i++)
132 dayread[i-from] = string[i];
133 for (i=0; i<7; i++)
134 if (strcmp(dayread, days_str[i]) == 0)
135 {
136 *days |= days_of_week[i];
137 free(dayread);
138 return 1;
139 }
140 /* if we are here, we didn't read a valid day */
141 free(dayread);
142 return 0;
143}
144
145static void
146parse_days_string(int *days, const char *daystring)
147{
148 int len;
149 int i=0;
150 char *err = "invalid days `%s' specified, should be Sun,Mon,Tue... format";
151
152 len = strlen(daystring);
153 if (len < 3)
154 exit_error(PARAMETER_PROBLEM, err, daystring);
155 while(i<len)
156 {
157 if (parse_day(days, i, i+3, daystring) == 0)
158 exit_error(PARAMETER_PROBLEM, err, daystring);
159 i += 4;
160 }
161}
162
163#define IPT_TIME_START 0x01
164#define IPT_TIME_STOP 0x02
165#define IPT_TIME_DAYS 0x04
166
167
168/* Function which parses command options; returns true if it
169 ate an option */
170static int
171parse(int c, char **argv, int invert, unsigned int *flags,
172 const struct ipt_entry *entry,
173 unsigned int *nfcache,
174 struct ipt_entry_match **match)
175{
176 struct ipt_time_info *timeinfo = (struct ipt_time_info *)(*match)->data;
Fabrice MARIE358a33e2001-10-02 15:44:02 +0000177 int hours, minutes;
Harald Welte5ea4bcb2001-03-25 19:25:41 +0000178
179 switch (c)
180 {
181 /* timestart */
182 case '1':
183 if (invert)
184 exit_error(PARAMETER_PROBLEM,
185 "unexpected '!' with --timestart");
186 if (*flags & IPT_TIME_START)
187 exit_error(PARAMETER_PROBLEM,
188 "Can't specify --timestart twice");
189 parse_time_string(&hours, &minutes, optarg);
Fabrice MARIEd7e251f2001-04-27 08:39:00 +0000190 timeinfo->time_start = (hours * 60) + minutes;
Harald Welte5ea4bcb2001-03-25 19:25:41 +0000191 *flags |= IPT_TIME_START;
192 break;
193 /* timestop */
194 case '2':
195 if (invert)
196 exit_error(PARAMETER_PROBLEM,
197 "unexpected '!' with --timestop");
198 if (*flags & IPT_TIME_STOP)
199 exit_error(PARAMETER_PROBLEM,
200 "Can't specify --timestop twice");
201 parse_time_string(&hours, &minutes, optarg);
Fabrice MARIEd7e251f2001-04-27 08:39:00 +0000202 timeinfo->time_stop = (hours * 60) + minutes;
Harald Welte5ea4bcb2001-03-25 19:25:41 +0000203 *flags |= IPT_TIME_STOP;
204 break;
205
206 /* days */
207 case '3':
208 if (invert)
209 exit_error(PARAMETER_PROBLEM,
210 "unexpected '!' with --days");
211 if (*flags & IPT_TIME_DAYS)
212 exit_error(PARAMETER_PROBLEM,
213 "Can't specify --days twice");
Fabrice MARIE358a33e2001-10-02 15:44:02 +0000214 parse_days_string(&globaldays, optarg);
215 timeinfo->days_match = globaldays;
Harald Welte5ea4bcb2001-03-25 19:25:41 +0000216 *flags |= IPT_TIME_DAYS;
217 break;
218 default:
219 return 0;
220 }
221 return 1;
222}
223
Harald Welte48ea5852001-12-07 10:57:33 +0000224/* Final check; must have specified --timestart --timestop --days. */
Harald Welte5ea4bcb2001-03-25 19:25:41 +0000225static void
226final_check(unsigned int flags)
227{
228 if (flags != (IPT_TIME_START | IPT_TIME_STOP | IPT_TIME_DAYS))
229 exit_error(PARAMETER_PROBLEM,
Harald Welte48ea5852001-12-07 10:57:33 +0000230 "TIME match: You must specify `--timestart --timestop and --days'");
Harald Welte5ea4bcb2001-03-25 19:25:41 +0000231}
232
233
234static void
235print_days(int daynum)
236{
237 char *days[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
238 unsigned short int days_of_week[7] = {64, 32, 16, 8, 4, 2, 1};
239 unsigned short int i, nbdays=0;
240
241 for (i=0; i<7; i++) {
242 if ((days_of_week[i] & daynum) == days_of_week[i])
243 {
244 if (nbdays>0)
245 printf(",%s", days[i]);
246 else
247 printf("%s", days[i]);
248 ++nbdays;
249 }
250 }
251}
252
Fabrice MARIEd7e251f2001-04-27 08:39:00 +0000253static void
254divide_time(int fulltime, int *hours, int *minutes)
255{
256 *hours = fulltime / 60;
257 *minutes = fulltime % 60;
258}
259
Harald Welte5ea4bcb2001-03-25 19:25:41 +0000260/* Prints out the matchinfo. */
261static void
262print(const struct ipt_ip *ip,
263 const struct ipt_entry_match *match,
264 int numeric)
265{
266 struct ipt_time_info *time = ((struct ipt_time_info *)match->data);
Fabrice MARIEd7e251f2001-04-27 08:39:00 +0000267 int hour_start, hour_stop, minute_start, minute_stop;
268
269 divide_time(time->time_start, &hour_start, &minute_start);
270 divide_time(time->time_stop, &hour_stop, &minute_stop);
Harald Welte5ea4bcb2001-03-25 19:25:41 +0000271 printf(" TIME from %d:%d to %d:%d on ",
Fabrice MARIEd7e251f2001-04-27 08:39:00 +0000272 hour_start, minute_start,
273 hour_stop, minute_stop);
Harald Welte5ea4bcb2001-03-25 19:25:41 +0000274 print_days(time->days_match);
275 printf(" ");
276}
277
278/* Saves the data in parsable form to stdout. */
279static void
280save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
281{
282 struct ipt_time_info *time = ((struct ipt_time_info *)match->data);
Fabrice MARIEd7e251f2001-04-27 08:39:00 +0000283 int hour_start, hour_stop, minute_start, minute_stop;
Harald Welte5ea4bcb2001-03-25 19:25:41 +0000284
Fabrice MARIEd7e251f2001-04-27 08:39:00 +0000285 divide_time(time->time_start, &hour_start, &minute_start);
286 divide_time(time->time_stop, &hour_stop, &minute_stop);
Harald Welte5ea4bcb2001-03-25 19:25:41 +0000287 printf(" --timestart %.2d:%.2d --timestop %.2d:%.2d --days ",
Fabrice MARIEd7e251f2001-04-27 08:39:00 +0000288 hour_start, minute_start,
289 hour_stop, minute_stop);
Harald Welte5ea4bcb2001-03-25 19:25:41 +0000290 print_days(time->days_match);
291 printf(" ");
292}
293
Harald Welte3efb6ea2001-08-06 18:50:21 +0000294static
Harald Welte5ea4bcb2001-03-25 19:25:41 +0000295struct iptables_match timestruct
296= { NULL,
297 "time",
Harald Welte80fe35d2002-05-29 13:08:15 +0000298 IPTABLES_VERSION,
Harald Welte5ea4bcb2001-03-25 19:25:41 +0000299 IPT_ALIGN(sizeof(struct ipt_time_info)),
300 IPT_ALIGN(sizeof(struct ipt_time_info)),
301 &help,
302 &init,
303 &parse,
304 &final_check,
305 &print,
306 &save,
307 opts
308};
309
310void _init(void)
311{
312 register_match(&timestruct);
313}