1 #include <stdbool.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <xtables.h>
5 #include <linux/netfilter/xt_recent.h>
6
7 enum {
8 O_SET = 0,
9 O_RCHECK,
10 O_UPDATE,
11 O_REMOVE,
12 O_SECONDS,
13 O_HITCOUNT,
14 O_RTTL,
15 O_NAME,
16 O_RSOURCE,
17 O_RDEST,
18 F_SET = 1 << O_SET,
19 F_RCHECK = 1 << O_RCHECK,
20 F_UPDATE = 1 << O_UPDATE,
21 F_REMOVE = 1 << O_REMOVE,
22 F_ANY_OP = F_SET | F_RCHECK | F_UPDATE | F_REMOVE,
23 };
24
25 #define s struct xt_recent_mtinfo
26 static const struct xt_option_entry recent_opts[] = {
27 {.name = "set", .id = O_SET, .type = XTTYPE_NONE,
28 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
29 {.name = "rcheck", .id = O_RCHECK, .type = XTTYPE_NONE,
30 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
31 {.name = "update", .id = O_UPDATE, .type = XTTYPE_NONE,
32 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
33 {.name = "remove", .id = O_REMOVE, .type = XTTYPE_NONE,
34 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
35 {.name = "seconds", .id = O_SECONDS, .type = XTTYPE_UINT32,
36 .flags = XTOPT_PUT, XTOPT_POINTER(s, seconds)},
37 {.name = "hitcount", .id = O_HITCOUNT, .type = XTTYPE_UINT32,
38 .flags = XTOPT_PUT, XTOPT_POINTER(s, hit_count)},
39 {.name = "rttl", .id = O_RTTL, .type = XTTYPE_NONE,
40 .excl = F_SET | F_REMOVE},
41 {.name = "name", .id = O_NAME, .type = XTTYPE_STRING,
42 .flags = XTOPT_PUT, XTOPT_POINTER(s, name)},
43 {.name = "rsource", .id = O_RSOURCE, .type = XTTYPE_NONE},
44 {.name = "rdest", .id = O_RDEST, .type = XTTYPE_NONE},
45 XTOPT_TABLEEND,
46 };
47 #undef s
48
recent_help(void)49 static void recent_help(void)
50 {
51 printf(
52 "recent match options:\n"
53 "[!] --set Add source address to list, always matches.\n"
54 "[!] --rcheck Match if source address in list.\n"
55 "[!] --update Match if source address in list, also update last-seen time.\n"
56 "[!] --remove Match if source address in list, also removes that address from list.\n"
57 " --seconds seconds For check and update commands above.\n"
58 " Specifies that the match will only occur if source address last seen within\n"
59 " the last 'seconds' seconds.\n"
60 " --hitcount hits For check and update commands above.\n"
61 " Specifies that the match will only occur if source address seen hits times.\n"
62 " May be used in conjunction with the seconds option.\n"
63 " --rttl For check and update commands above.\n"
64 " Specifies that the match will only occur if the source address and the TTL\n"
65 " match between this packet and the one which was set.\n"
66 " Useful if you have problems with people spoofing their source address in order\n"
67 " to DoS you via this module.\n"
68 " --name name Name of the recent list to be used. DEFAULT used if none given.\n"
69 " --rsource Match/Save the source address of each packet in the recent list table (default).\n"
70 " --rdest Match/Save the destination address of each packet in the recent list table.\n"
71 "xt_recent by: Stephen Frost <sfrost@snowman.net>. http://snowman.net/projects/ipt_recent/\n");
72 }
73
recent_init(struct xt_entry_match * match)74 static void recent_init(struct xt_entry_match *match)
75 {
76 struct xt_recent_mtinfo *info = (void *)(match)->data;
77
78 strncpy(info->name,"DEFAULT", XT_RECENT_NAME_LEN);
79 /* even though XT_RECENT_NAME_LEN is currently defined as 200,
80 * better be safe, than sorry */
81 info->name[XT_RECENT_NAME_LEN-1] = '\0';
82 info->side = XT_RECENT_SOURCE;
83 }
84
recent_parse(struct xt_option_call * cb)85 static void recent_parse(struct xt_option_call *cb)
86 {
87 struct xt_recent_mtinfo *info = cb->data;
88
89 xtables_option_parse(cb);
90 switch (cb->entry->id) {
91 case O_SET:
92 info->check_set |= XT_RECENT_SET;
93 if (cb->invert)
94 info->invert = true;
95 break;
96 case O_RCHECK:
97 info->check_set |= XT_RECENT_CHECK;
98 if (cb->invert)
99 info->invert = true;
100 break;
101 case O_UPDATE:
102 info->check_set |= XT_RECENT_UPDATE;
103 if (cb->invert)
104 info->invert = true;
105 break;
106 case O_REMOVE:
107 info->check_set |= XT_RECENT_REMOVE;
108 if (cb->invert)
109 info->invert = true;
110 break;
111 case O_RTTL:
112 info->check_set |= XT_RECENT_TTL;
113 break;
114 case O_RSOURCE:
115 info->side = XT_RECENT_SOURCE;
116 break;
117 case O_RDEST:
118 info->side = XT_RECENT_DEST;
119 break;
120 }
121 }
122
recent_check(struct xt_fcheck_call * cb)123 static void recent_check(struct xt_fcheck_call *cb)
124 {
125 if (!(cb->xflags & F_ANY_OP))
126 xtables_error(PARAMETER_PROBLEM,
127 "recent: you must specify one of `--set', `--rcheck' "
128 "`--update' or `--remove'");
129 }
130
recent_print(const void * ip,const struct xt_entry_match * match,int numeric)131 static void recent_print(const void *ip, const struct xt_entry_match *match,
132 int numeric)
133 {
134 const struct xt_recent_mtinfo *info = (const void *)match->data;
135
136 if (info->invert)
137 printf(" !");
138
139 printf(" recent:");
140 if (info->check_set & XT_RECENT_SET)
141 printf(" SET");
142 if (info->check_set & XT_RECENT_CHECK)
143 printf(" CHECK");
144 if (info->check_set & XT_RECENT_UPDATE)
145 printf(" UPDATE");
146 if (info->check_set & XT_RECENT_REMOVE)
147 printf(" REMOVE");
148 if(info->seconds) printf(" seconds: %d", info->seconds);
149 if(info->hit_count) printf(" hit_count: %d", info->hit_count);
150 if (info->check_set & XT_RECENT_TTL)
151 printf(" TTL-Match");
152 if(info->name) printf(" name: %s", info->name);
153 if (info->side == XT_RECENT_SOURCE)
154 printf(" side: source");
155 if (info->side == XT_RECENT_DEST)
156 printf(" side: dest");
157 }
158
recent_save(const void * ip,const struct xt_entry_match * match)159 static void recent_save(const void *ip, const struct xt_entry_match *match)
160 {
161 const struct xt_recent_mtinfo *info = (const void *)match->data;
162
163 if (info->invert)
164 printf(" !");
165
166 if (info->check_set & XT_RECENT_SET)
167 printf(" --set");
168 if (info->check_set & XT_RECENT_CHECK)
169 printf(" --rcheck");
170 if (info->check_set & XT_RECENT_UPDATE)
171 printf(" --update");
172 if (info->check_set & XT_RECENT_REMOVE)
173 printf(" --remove");
174 if(info->seconds) printf(" --seconds %d", info->seconds);
175 if(info->hit_count) printf(" --hitcount %d", info->hit_count);
176 if (info->check_set & XT_RECENT_TTL)
177 printf(" --rttl");
178 if(info->name) printf(" --name %s",info->name);
179 if (info->side == XT_RECENT_SOURCE)
180 printf(" --rsource");
181 if (info->side == XT_RECENT_DEST)
182 printf(" --rdest");
183 }
184
185 static struct xtables_match recent_mt_reg = {
186 .name = "recent",
187 .version = XTABLES_VERSION,
188 .family = NFPROTO_UNSPEC,
189 .size = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
190 .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
191 .help = recent_help,
192 .init = recent_init,
193 .x6_parse = recent_parse,
194 .x6_fcheck = recent_check,
195 .print = recent_print,
196 .save = recent_save,
197 .x6_options = recent_opts,
198 };
199
_init(void)200 void _init(void)
201 {
202 xtables_register_match(&recent_mt_reg);
203 }
204