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 <getopt.h>
7
8#include <iptables.h>
9#include <linux/netfilter_ipv4/ipt_time.h>
10#include <time.h>
11
12/* Function which prints out usage message. */
13static void
14help(void)
15{
16	printf(
17"TIME v%s options:\n"
18" --timestart value --timestop value --days listofdays\n"
19"          timestart value : HH:MM:SS\n"
20"          timestop  value : HH:MM:SS\n"
21"          listofdays value: a list of days to apply -> ie. Mon,Tue,Wed,Thu,Fri. Case sensitive\n",
22IPTABLES_VERSION);
23}
24
25static struct option opts[] = {
26	{ "timestart", 1, 0, '1' },
27	{ "timestop", 1, 0, '2' },
28	{ "days", 1, 0, '3'},
29	{0}
30};
31
32/* Initialize the match. */
33static void
34init(struct ipt_entry_match *m, unsigned int *nfcache)
35{
36	/* caching not yet implemented */
37        *nfcache |= NFC_UNKNOWN;
38}
39
40static int
41parse_time(const char *time)
42{
43	int hours, minutes, seconds;
44
45	if (sscanf(time, "%d:%d:%d", &hours, &minutes, &seconds) == 3)
46		return (hours * 60 * 60 + minutes * 60 + seconds);
47
48	/* If we are here, there was a problem ..*/
49	exit_error(PARAMETER_PROBLEM,
50		   "invalid time `%s' specified, should be HH:MM:SS format", time);
51}
52
53static const char *days[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
54
55static int
56parse_days(const char *string)
57{
58	char *comma;
59	int i, mask = 0;
60
61	do {
62		for (i = 0; i < 7; i++)
63			if (!strncasecmp(string, days[i], 3))
64				mask |= 1 << i;
65		comma = strchr(string, ',');
66		string = comma + 1;
67	} while (comma);
68
69	return mask;
70}
71
72#define IPT_TIME_START 0x01
73#define IPT_TIME_STOP  0x02
74#define IPT_TIME_DAYS  0x04
75
76
77/* Function which parses command options; returns true if it
78   ate an option */
79static int
80parse(int c, char **argv, int invert, unsigned int *flags,
81      const struct ipt_entry *entry,
82      unsigned int *nfcache,
83      struct ipt_entry_match **match)
84{
85	struct ipt_time_info *timeinfo = (struct ipt_time_info *)(*match)->data;
86
87	switch (c)
88	{
89		/* timestart */
90	case '1':
91		if (invert)
92			exit_error(PARAMETER_PROBLEM,
93                                   "unexpected '!' with --timestart");
94		if (*flags & IPT_TIME_START)
95                        exit_error(PARAMETER_PROBLEM,
96                                   "Can't specify --timestart twice");
97		timeinfo->time_start = parse_time(optarg);
98		*flags |= IPT_TIME_START;
99		break;
100		/* timestop */
101	case '2':
102		if (invert)
103			exit_error(PARAMETER_PROBLEM,
104                                   "unexpected '!' with --timestop");
105		if (*flags & IPT_TIME_STOP)
106                        exit_error(PARAMETER_PROBLEM,
107                                   "Can't specify --timestop twice");
108		timeinfo->time_stop = parse_time(optarg);
109		*flags |= IPT_TIME_STOP;
110		break;
111
112		/* days */
113	case '3':
114		if (invert)
115			exit_error(PARAMETER_PROBLEM,
116                                   "unexpected '!' with --days");
117		if (*flags & IPT_TIME_DAYS)
118                        exit_error(PARAMETER_PROBLEM,
119                                   "Can't specify --days twice");
120		timeinfo->days_match = parse_days(optarg);
121		*flags |= IPT_TIME_DAYS;
122		break;
123	default:
124		return 0;
125	}
126	return 1;
127}
128
129/* Final check; must have specified --timestart --timestop --days. */
130static void
131final_check(unsigned int flags)
132{
133	if (flags != (IPT_TIME_START | IPT_TIME_STOP | IPT_TIME_DAYS))
134		exit_error(PARAMETER_PROBLEM,
135			   "TIME match: You must specify `--timestart --timestop and --days'");
136}
137
138static void
139print_days(const struct ipt_time_info *time)
140{
141	int i;
142	char *sep = "";
143
144	for (i = 0; i < 7; i++) {
145		if (time->days_match & (1 << i)) {
146			printf("%s%s", sep, days[i]);
147			sep = ",";
148		}
149	}
150}
151
152/* Prints out the matchinfo. */
153static void
154print(const struct ipt_ip *ip,
155      const struct ipt_entry_match *match,
156      int numeric)
157{
158	struct ipt_time_info *time = ((struct ipt_time_info *)match->data);
159
160	printf(" TIME from %02d:%02d:%02d to %02d:%02d:%02d on ",
161	       time->time_start / (60 * 60), (time->time_start / 60) % 60, time->time_start % 60,
162	       time->time_stop / (60 * 60), (time->time_stop / 60) % 60, time->time_stop % 60);
163	print_days(time);
164	printf(" ");
165}
166
167/* Saves the data in parsable form to stdout. */
168static void
169save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
170{
171	struct ipt_time_info *time = ((struct ipt_time_info *)match->data);
172
173	printf(" --timestart %02d:%02d:%02d --timestop %02d:%02d:%02d --days ",
174	       time->time_start / (60 * 60), (time->time_start / 60) % 60, time->time_start % 60,
175	       time->time_stop / (60 * 60), (time->time_stop / 60) % 60, time->time_stop % 60);
176	print_days(time);
177	printf(" ");
178}
179
180static
181struct iptables_match timestruct
182= { NULL,
183    "time",
184    IPTABLES_VERSION,
185    IPT_ALIGN(sizeof(struct ipt_time_info)),
186    IPT_ALIGN(sizeof(struct ipt_time_info)),
187    &help,
188    &init,
189    &parse,
190    &final_check,
191    &print,
192    &save,
193    opts
194};
195
196void _init(void)
197{
198	register_match(&timestruct);
199}
200