fix for f12, gcc4.4
[iptables.git] / extensions / libipt_recent.c
1 /* Shared library add-on to iptables to add recent 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_recent.h>
10
11 /* Need these in order to not fail when compiling against an older kernel. */
12 #ifndef RECENT_NAME
13 #define RECENT_NAME     "ipt_recent"
14 #endif /* RECENT_NAME */
15
16 #ifndef RECENT_VER
17 #define RECENT_VER      "unknown"
18 #endif /* RECENT_VER */
19
20 #ifndef IPT_RECENT_NAME_LEN
21 #define IPT_RECENT_NAME_LEN     200
22 #endif /* IPT_RECENT_NAME_LEN */
23
24 /* Options for this module */
25 static struct option opts[] = {
26         { .name = "set",      .has_arg = 0, .flag = 0, .val = 201 }, 
27         { .name = "rcheck",   .has_arg = 0, .flag = 0, .val = 202 }, 
28         { .name = "update",   .has_arg = 0, .flag = 0, .val = 203 },
29         { .name = "seconds",  .has_arg = 1, .flag = 0, .val = 204 }, 
30         { .name = "hitcount", .has_arg = 1, .flag = 0, .val = 205 },
31         { .name = "remove",   .has_arg = 0, .flag = 0, .val = 206 },
32         { .name = "rttl",     .has_arg = 0, .flag = 0, .val = 207 },
33         { .name = "name",     .has_arg = 1, .flag = 0, .val = 208 },
34         { .name = "rsource",  .has_arg = 0, .flag = 0, .val = 209 },
35         { .name = "rdest",    .has_arg = 0, .flag = 0, .val = 210 },
36         { .name = 0,          .has_arg = 0, .flag = 0, .val = 0   }
37 };
38
39 /* Function which prints out usage message. */
40 static void
41 help(void)
42 {
43         printf(
44 "recent v%s options:\n"
45 "[!] --set                       Add source address to list, always matches.\n"
46 "[!] --rcheck                    Match if source address in list.\n"
47 "[!] --update                    Match if source address in list, also update last-seen time.\n"
48 "[!] --remove                    Match if source address in list, also removes that address from list.\n"
49 "    --seconds seconds           For check and update commands above.\n"
50 "                                Specifies that the match will only occur if source address last seen within\n"
51 "                                the last 'seconds' seconds.\n"
52 "    --hitcount hits             For check and update commands above.\n"
53 "                                Specifies that the match will only occur if source address seen hits times.\n"
54 "                                May be used in conjunction with the seconds option.\n"
55 "    --rttl                      For check and update commands above.\n"
56 "                                Specifies that the match will only occur if the source address and the TTL\n"
57 "                                match between this packet and the one which was set.\n"
58 "                                Useful if you have problems with people spoofing their source address in order\n"
59 "                                to DoS you via this module.\n"
60 "    --name name                 Name of the recent list to be used.  DEFAULT used if none given.\n"
61 "    --rsource                   Match/Save the source address of each packet in the recent list table (default).\n"
62 "    --rdest                     Match/Save the destination address of each packet in the recent list table.\n"
63 RECENT_NAME " " RECENT_VER ": Stephen Frost <sfrost@snowman.net>.  http://snowman.net/projects/ipt_recent/\n"
64 ,
65 IPTABLES_VERSION);
66
67 }
68   
69 /* Initialize the match. */
70 static void
71 init(struct ipt_entry_match *match, unsigned int *nfcache)
72 {
73         struct ipt_recent_info *info = (struct ipt_recent_info *)(match)->data;
74
75
76         strncpy(info->name,"DEFAULT",IPT_RECENT_NAME_LEN);
77         /* eventhough IPT_RECENT_NAME_LEN is currently defined as 200,
78          * better be safe, than sorry */
79         info->name[IPT_RECENT_NAME_LEN-1] = '\0';
80         info->side = IPT_RECENT_SOURCE;
81 }
82
83 /* Function which parses command options; returns true if it
84    ate an option */
85 static int
86 parse(int c, char **argv, int invert, unsigned int *flags,
87       const struct ipt_entry *entry,
88       unsigned int *nfcache,
89       struct ipt_entry_match **match)
90 {
91         struct ipt_recent_info *info = (struct ipt_recent_info *)(*match)->data;
92         switch (c) {
93                 case 201:
94                         if (*flags) exit_error(PARAMETER_PROBLEM,
95                                         "recent: only one of `--set', `--rcheck' "
96                                         "`--update' or `--remove' may be set");
97                         check_inverse(optarg, &invert, &optind, 0);
98                         info->check_set |= IPT_RECENT_SET;
99                         if (invert) info->invert = 1;
100                         *flags = 1;
101                         break;
102                         
103                 case 202:
104                         if (*flags) exit_error(PARAMETER_PROBLEM,
105                                         "recent: only one of `--set', `--rcheck' "
106                                         "`--update' or `--remove' may be set");
107                         check_inverse(optarg, &invert, &optind, 0);
108                         info->check_set |= IPT_RECENT_CHECK;
109                         if(invert) info->invert = 1;
110                         *flags = 1;
111                         break;
112
113                 case 203:
114                         if (*flags) exit_error(PARAMETER_PROBLEM,
115                                         "recent: only one of `--set', `--rcheck' "
116                                         "`--update' or `--remove' may be set");
117                         check_inverse(optarg, &invert, &optind, 0);
118                         info->check_set |= IPT_RECENT_UPDATE;
119                         if (invert) info->invert = 1;
120                         *flags = 1;
121                         break;
122
123                 case 206:
124                         if (*flags) exit_error(PARAMETER_PROBLEM,
125                                         "recent: only one of `--set', `--rcheck' "
126                                         "`--update' or `--remove' may be set");
127                         check_inverse(optarg, &invert, &optind, 0);
128                         info->check_set |= IPT_RECENT_REMOVE;
129                         if (invert) info->invert = 1;
130                         *flags = 1;
131                         break;
132
133                 case 204:
134                         info->seconds = atoi(optarg);
135                         break;
136
137                 case 205:
138                         info->hit_count = atoi(optarg);
139                         break;
140
141                 case 207:
142                         info->check_set |= IPT_RECENT_TTL;
143                         break;
144
145                 case 208:
146                         strncpy(info->name,optarg,IPT_RECENT_NAME_LEN);
147                         info->name[IPT_RECENT_NAME_LEN-1] = '\0';
148                         break;
149
150                 case 209:
151                         info->side = IPT_RECENT_SOURCE;
152                         break;
153
154                 case 210:
155                         info->side = IPT_RECENT_DEST;
156                         break;
157
158                 default:
159                         return 0;
160         }
161
162         return 1;
163 }
164
165 /* Final check; must have specified a specific option. */
166 static void
167 final_check(unsigned int flags)
168 {
169
170         if (!flags)
171                 exit_error(PARAMETER_PROBLEM,
172                         "recent: you must specify one of `--set', `--rcheck' "
173                         "`--update' or `--remove'");
174 }
175
176 /* Prints out the matchinfo. */
177 static void
178 print(const struct ipt_ip *ip,
179       const struct ipt_entry_match *match,
180       int numeric)
181 {
182         struct ipt_recent_info *info = (struct ipt_recent_info *)match->data;
183
184         if (info->invert)
185                 fputc('!', stdout);
186
187         printf("recent: ");
188         if(info->check_set & IPT_RECENT_SET) printf("SET ");
189         if(info->check_set & IPT_RECENT_CHECK) printf("CHECK ");
190         if(info->check_set & IPT_RECENT_UPDATE) printf("UPDATE ");
191         if(info->check_set & IPT_RECENT_REMOVE) printf("REMOVE ");
192         if(info->seconds) printf("seconds: %d ",info->seconds);
193         if(info->hit_count) printf("hit_count: %d ",info->hit_count);
194         if(info->check_set & IPT_RECENT_TTL) printf("TTL-Match ");
195         if(info->name) printf("name: %s ",info->name);
196         if(info->side == IPT_RECENT_SOURCE) printf("side: source ");
197         if(info->side == IPT_RECENT_DEST) printf("side: dest");
198 }
199
200 /* Saves the union ipt_matchinfo in parsable form to stdout. */
201 static void
202 save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
203 {
204         struct ipt_recent_info *info = (struct ipt_recent_info *)match->data;
205
206         if (info->invert)
207                 printf("! ");
208
209         if(info->check_set & IPT_RECENT_SET) printf("--set ");
210         if(info->check_set & IPT_RECENT_CHECK) printf("--rcheck ");
211         if(info->check_set & IPT_RECENT_UPDATE) printf("--update ");
212         if(info->check_set & IPT_RECENT_REMOVE) printf("--remove ");
213         if(info->seconds) printf("--seconds %d ",info->seconds);
214         if(info->hit_count) printf("--hitcount %d ",info->hit_count);
215         if(info->check_set & IPT_RECENT_TTL) printf("--rttl ");
216         if(info->name) printf("--name %s ",info->name);
217         if(info->side == IPT_RECENT_SOURCE) printf("--rsource ");
218         if(info->side == IPT_RECENT_DEST) printf("--rdest ");
219 }
220
221 /* Structure for iptables to use to communicate with module */
222 static struct iptables_match recent = { 
223     .next          = NULL,
224     .name          = "recent",
225     .version       = IPTABLES_VERSION,
226     .size          = IPT_ALIGN(sizeof(struct ipt_recent_info)),
227     .userspacesize = IPT_ALIGN(sizeof(struct ipt_recent_info)),
228     .help          = &help,
229     .init          = &init,
230     .parse         = &parse,
231     .final_check   = &final_check,
232     .print         = &print,
233     .save          = &save,
234     .extra_opts    = opts
235 };
236
237 void _init(void)
238 {
239         register_match(&recent);
240 }