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