iptables-1.2.9-2.3.1.src.rpm
[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         *nfcache |= NFC_UNKNOWN;
76
77         strncpy(info->name,"DEFAULT",IPT_RECENT_NAME_LEN);
78         info->side = IPT_RECENT_SOURCE;
79 }
80
81 /* Function which parses command options; returns true if it
82    ate an option */
83 static int
84 parse(int c, char **argv, int invert, unsigned int *flags,
85       const struct ipt_entry *entry,
86       unsigned int *nfcache,
87       struct ipt_entry_match **match)
88 {
89         struct ipt_recent_info *info = (struct ipt_recent_info *)(*match)->data;
90         switch (c) {
91                 case 201:
92                         if (*flags) exit_error(PARAMETER_PROBLEM,
93                                         "recent: only one of `--set', `--rcheck' "
94                                         "`--update' or `--remove' may be set");
95                         check_inverse(optarg, &invert, &optind, 0);
96                         info->check_set |= IPT_RECENT_SET;
97                         if (invert) info->invert = 1;
98                         *flags = 1;
99                         break;
100                         
101                 case 202:
102                         if (*flags) exit_error(PARAMETER_PROBLEM,
103                                         "recent: only one of `--set', `--rcheck' "
104                                         "`--update' or `--remove' may be set");
105                         check_inverse(optarg, &invert, &optind, 0);
106                         info->check_set |= IPT_RECENT_CHECK;
107                         if(invert) info->invert = 1;
108                         *flags = 1;
109                         break;
110
111                 case 203:
112                         if (*flags) exit_error(PARAMETER_PROBLEM,
113                                         "recent: only one of `--set', `--rcheck' "
114                                         "`--update' or `--remove' may be set");
115                         check_inverse(optarg, &invert, &optind, 0);
116                         info->check_set |= IPT_RECENT_UPDATE;
117                         if (invert) info->invert = 1;
118                         *flags = 1;
119                         break;
120
121                 case 206:
122                         if (*flags) exit_error(PARAMETER_PROBLEM,
123                                         "recent: only one of `--set', `--rcheck' "
124                                         "`--update' or `--remove' may be set");
125                         check_inverse(optarg, &invert, &optind, 0);
126                         info->check_set |= IPT_RECENT_REMOVE;
127                         if (invert) info->invert = 1;
128                         *flags = 1;
129                         break;
130
131                 case 204:
132                         info->seconds = atoi(optarg);
133                         break;
134
135                 case 205:
136                         info->hit_count = atoi(optarg);
137                         break;
138
139                 case 207:
140                         info->check_set |= IPT_RECENT_TTL;
141                         break;
142
143                 case 208:
144                         strncpy(info->name,optarg,IPT_RECENT_NAME_LEN);
145                         break;
146
147                 case 209:
148                         info->side = IPT_RECENT_SOURCE;
149                         break;
150
151                 case 210:
152                         info->side = IPT_RECENT_DEST;
153                         break;
154
155                 default:
156                         return 0;
157         }
158
159         return 1;
160 }
161
162 /* Final check; must have specified a specific option. */
163 static void
164 final_check(unsigned int flags)
165 {
166
167         if (!flags)
168                 exit_error(PARAMETER_PROBLEM,
169                         "recent: you must specify one of `--set', `--rcheck' "
170                         "`--update' or `--remove'");
171 }
172
173 /* Prints out the matchinfo. */
174 static void
175 print(const struct ipt_ip *ip,
176       const struct ipt_entry_match *match,
177       int numeric)
178 {
179         struct ipt_recent_info *info = (struct ipt_recent_info *)match->data;
180
181         if (info->invert)
182                 fputc('!', stdout);
183
184         printf("recent: ");
185         if(info->check_set & IPT_RECENT_SET) printf("SET ");
186         if(info->check_set & IPT_RECENT_CHECK) printf("CHECK ");
187         if(info->check_set & IPT_RECENT_UPDATE) printf("UPDATE ");
188         if(info->check_set & IPT_RECENT_REMOVE) printf("REMOVE ");
189         if(info->seconds) printf("seconds: %d ",info->seconds);
190         if(info->hit_count) printf("hit_count: %d ",info->hit_count);
191         if(info->check_set & IPT_RECENT_TTL) printf("TTL-Match ");
192         if(info->name) printf("name: %s ",info->name);
193         if(info->side == IPT_RECENT_SOURCE) printf("side: source ");
194         if(info->side == IPT_RECENT_DEST) printf("side: dest");
195 }
196
197 /* Saves the union ipt_matchinfo in parsable form to stdout. */
198 static void
199 save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
200 {
201         struct ipt_recent_info *info = (struct ipt_recent_info *)match->data;
202
203         if (info->invert)
204                 printf("! ");
205
206         if(info->check_set & IPT_RECENT_SET) printf("--set ");
207         if(info->check_set & IPT_RECENT_CHECK) printf("--rcheck ");
208         if(info->check_set & IPT_RECENT_UPDATE) printf("--update ");
209         if(info->check_set & IPT_RECENT_REMOVE) printf("--remove ");
210         if(info->seconds) printf("--seconds %d ",info->seconds);
211         if(info->hit_count) printf("--hitcount %d ",info->hit_count);
212         if(info->check_set & IPT_RECENT_TTL) printf("--rttl ");
213         if(info->name) printf("--name %s ",info->name);
214         if(info->side == IPT_RECENT_SOURCE) printf("--rsource ");
215         if(info->side == IPT_RECENT_DEST) printf("--rdest ");
216 }
217
218 /* Structure for iptables to use to communicate with module */
219 static struct iptables_match recent = { 
220     .next          = NULL,
221     .name          = "recent",
222     .version       = IPTABLES_VERSION,
223     .size          = IPT_ALIGN(sizeof(struct ipt_recent_info)),
224     .userspacesize = IPT_ALIGN(sizeof(struct ipt_recent_info)),
225     .help          = &help,
226     .init          = &init,
227     .parse         = &parse,
228     .final_check   = &final_check,
229     .print         = &print,
230     .save          = &save,
231     .extra_opts    = opts
232 };
233
234 void _init(void)
235 {
236         register_match(&recent);
237 }