Home | History | Annotate | Download | only in extensions
      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_REAP,
     14 	O_HITCOUNT,
     15 	O_RTTL,
     16 	O_NAME,
     17 	O_RSOURCE,
     18 	O_RDEST,
     19 	O_MASK,
     20 	F_SET    = 1 << O_SET,
     21 	F_RCHECK = 1 << O_RCHECK,
     22 	F_UPDATE = 1 << O_UPDATE,
     23 	F_REMOVE = 1 << O_REMOVE,
     24 	F_SECONDS = 1 << O_SECONDS,
     25 	F_ANY_OP = F_SET | F_RCHECK | F_UPDATE | F_REMOVE,
     26 };
     27 
     28 #define s struct xt_recent_mtinfo
     29 static const struct xt_option_entry recent_opts_v0[] = {
     30 	{.name = "set", .id = O_SET, .type = XTTYPE_NONE,
     31 	 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
     32 	{.name = "rcheck", .id = O_RCHECK, .type = XTTYPE_NONE,
     33 	 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
     34 	{.name = "update", .id = O_UPDATE, .type = XTTYPE_NONE,
     35 	 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
     36 	{.name = "remove", .id = O_REMOVE, .type = XTTYPE_NONE,
     37 	 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
     38 	{.name = "seconds", .id = O_SECONDS, .type = XTTYPE_UINT32,
     39 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, seconds), .min = 1},
     40 	{.name = "reap", .id = O_REAP, .type = XTTYPE_NONE,
     41 	 .also = F_SECONDS },
     42 	{.name = "hitcount", .id = O_HITCOUNT, .type = XTTYPE_UINT32,
     43 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, hit_count)},
     44 	{.name = "rttl", .id = O_RTTL, .type = XTTYPE_NONE,
     45 	 .excl = F_SET | F_REMOVE},
     46 	{.name = "name", .id = O_NAME, .type = XTTYPE_STRING,
     47 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, name)},
     48 	{.name = "rsource", .id = O_RSOURCE, .type = XTTYPE_NONE},
     49 	{.name = "rdest", .id = O_RDEST, .type = XTTYPE_NONE},
     50 	XTOPT_TABLEEND,
     51 };
     52 #undef s
     53 
     54 #define s struct xt_recent_mtinfo_v1
     55 static const struct xt_option_entry recent_opts_v1[] = {
     56 	{.name = "set", .id = O_SET, .type = XTTYPE_NONE,
     57 	 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
     58 	{.name = "rcheck", .id = O_RCHECK, .type = XTTYPE_NONE,
     59 	 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
     60 	{.name = "update", .id = O_UPDATE, .type = XTTYPE_NONE,
     61 	 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
     62 	{.name = "remove", .id = O_REMOVE, .type = XTTYPE_NONE,
     63 	 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
     64 	{.name = "seconds", .id = O_SECONDS, .type = XTTYPE_UINT32,
     65 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, seconds), .min = 1},
     66 	{.name = "reap", .id = O_REAP, .type = XTTYPE_NONE,
     67 	 .also = F_SECONDS },
     68 	{.name = "hitcount", .id = O_HITCOUNT, .type = XTTYPE_UINT32,
     69 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, hit_count)},
     70 	{.name = "rttl", .id = O_RTTL, .type = XTTYPE_NONE,
     71 	 .excl = F_SET | F_REMOVE},
     72 	{.name = "name", .id = O_NAME, .type = XTTYPE_STRING,
     73 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, name)},
     74 	{.name = "rsource", .id = O_RSOURCE, .type = XTTYPE_NONE},
     75 	{.name = "rdest", .id = O_RDEST, .type = XTTYPE_NONE},
     76 	{.name = "mask", .id = O_MASK, .type = XTTYPE_HOST,
     77 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, mask)},
     78 	XTOPT_TABLEEND,
     79 };
     80 #undef s
     81 
     82 static void recent_help(void)
     83 {
     84 	printf(
     85 "recent match options:\n"
     86 "[!] --set                       Add source address to list, always matches.\n"
     87 "[!] --rcheck                    Match if source address in list.\n"
     88 "[!] --update                    Match if source address in list, also update last-seen time.\n"
     89 "[!] --remove                    Match if source address in list, also removes that address from list.\n"
     90 "    --seconds seconds           For check and update commands above.\n"
     91 "                                Specifies that the match will only occur if source address last seen within\n"
     92 "                                the last 'seconds' seconds.\n"
     93 "    --reap                      Purge entries older then 'seconds'.\n"
     94 "                                Can only be used in conjunction with the seconds option.\n"
     95 "    --hitcount hits             For check and update commands above.\n"
     96 "                                Specifies that the match will only occur if source address seen hits times.\n"
     97 "                                May be used in conjunction with the seconds option.\n"
     98 "    --rttl                      For check and update commands above.\n"
     99 "                                Specifies that the match will only occur if the source address and the TTL\n"
    100 "                                match between this packet and the one which was set.\n"
    101 "                                Useful if you have problems with people spoofing their source address in order\n"
    102 "                                to DoS you via this module.\n"
    103 "    --name name                 Name of the recent list to be used.  DEFAULT used if none given.\n"
    104 "    --rsource                   Match/Save the source address of each packet in the recent list table (default).\n"
    105 "    --rdest                     Match/Save the destination address of each packet in the recent list table.\n"
    106 "    --mask netmask              Netmask that will be applied to this recent list.\n"
    107 "xt_recent by: Stephen Frost <sfrost (at) snowman.net>.  http://snowman.net/projects/ipt_recent/\n");
    108 }
    109 
    110 enum {
    111 	XT_RECENT_REV_0 = 0,
    112 	XT_RECENT_REV_1,
    113 };
    114 
    115 static void recent_init(struct xt_entry_match *match, unsigned int rev)
    116 {
    117 	struct xt_recent_mtinfo *info = (struct xt_recent_mtinfo *)match->data;
    118 	struct xt_recent_mtinfo_v1 *info_v1 =
    119 		(struct xt_recent_mtinfo_v1 *)match->data;
    120 
    121 	strncpy(info->name,"DEFAULT", XT_RECENT_NAME_LEN);
    122 	/* even though XT_RECENT_NAME_LEN is currently defined as 200,
    123 	 * better be safe, than sorry */
    124 	info->name[XT_RECENT_NAME_LEN-1] = '\0';
    125 	info->side = XT_RECENT_SOURCE;
    126 	if (rev == XT_RECENT_REV_1)
    127 		memset(&info_v1->mask, 0xFF, sizeof(info_v1->mask));
    128 }
    129 
    130 static void recent_parse(struct xt_option_call *cb)
    131 {
    132 	struct xt_recent_mtinfo *info = cb->data;
    133 
    134 	xtables_option_parse(cb);
    135 	switch (cb->entry->id) {
    136 	case O_SET:
    137 		info->check_set |= XT_RECENT_SET;
    138 		if (cb->invert)
    139 			info->invert = true;
    140 		break;
    141 	case O_RCHECK:
    142 		info->check_set |= XT_RECENT_CHECK;
    143 		if (cb->invert)
    144 			info->invert = true;
    145 		break;
    146 	case O_UPDATE:
    147 		info->check_set |= XT_RECENT_UPDATE;
    148 		if (cb->invert)
    149 			info->invert = true;
    150 		break;
    151 	case O_REMOVE:
    152 		info->check_set |= XT_RECENT_REMOVE;
    153 		if (cb->invert)
    154 			info->invert = true;
    155 		break;
    156 	case O_RTTL:
    157 		info->check_set |= XT_RECENT_TTL;
    158 		break;
    159 	case O_RSOURCE:
    160 		info->side = XT_RECENT_SOURCE;
    161 		break;
    162 	case O_RDEST:
    163 		info->side = XT_RECENT_DEST;
    164 		break;
    165 	case O_REAP:
    166 		info->check_set |= XT_RECENT_REAP;
    167 		break;
    168 	}
    169 }
    170 
    171 static void recent_check(struct xt_fcheck_call *cb)
    172 {
    173 	if (!(cb->xflags & F_ANY_OP))
    174 		xtables_error(PARAMETER_PROBLEM,
    175 			"recent: you must specify one of `--set', `--rcheck' "
    176 			"`--update' or `--remove'");
    177 }
    178 
    179 static void recent_print(const void *ip, const struct xt_entry_match *match,
    180                          unsigned int family)
    181 {
    182 	const struct xt_recent_mtinfo_v1 *info = (const void *)match->data;
    183 
    184 	if (info->invert)
    185 		printf(" !");
    186 
    187 	printf(" recent:");
    188 	if (info->check_set & XT_RECENT_SET)
    189 		printf(" SET");
    190 	if (info->check_set & XT_RECENT_CHECK)
    191 		printf(" CHECK");
    192 	if (info->check_set & XT_RECENT_UPDATE)
    193 		printf(" UPDATE");
    194 	if (info->check_set & XT_RECENT_REMOVE)
    195 		printf(" REMOVE");
    196 	if(info->seconds) printf(" seconds: %d", info->seconds);
    197 	if (info->check_set & XT_RECENT_REAP)
    198 		printf(" reap");
    199 	if(info->hit_count) printf(" hit_count: %d", info->hit_count);
    200 	if (info->check_set & XT_RECENT_TTL)
    201 		printf(" TTL-Match");
    202 	if(info->name) printf(" name: %s", info->name);
    203 	if (info->side == XT_RECENT_SOURCE)
    204 		printf(" side: source");
    205 	if (info->side == XT_RECENT_DEST)
    206 		printf(" side: dest");
    207 
    208 	switch(family) {
    209 	case NFPROTO_IPV4:
    210 		printf(" mask: %s",
    211 			xtables_ipaddr_to_numeric(&info->mask.in));
    212 		break;
    213 	case NFPROTO_IPV6:
    214 		printf(" mask: %s",
    215 			xtables_ip6addr_to_numeric(&info->mask.in6));
    216 		break;
    217 	}
    218 }
    219 
    220 static void recent_save(const void *ip, const struct xt_entry_match *match,
    221 			unsigned int family)
    222 {
    223 	const struct xt_recent_mtinfo_v1 *info = (const void *)match->data;
    224 
    225 	if (info->invert)
    226 		printf(" !");
    227 
    228 	if (info->check_set & XT_RECENT_SET)
    229 		printf(" --set");
    230 	if (info->check_set & XT_RECENT_CHECK)
    231 		printf(" --rcheck");
    232 	if (info->check_set & XT_RECENT_UPDATE)
    233 		printf(" --update");
    234 	if (info->check_set & XT_RECENT_REMOVE)
    235 		printf(" --remove");
    236 	if(info->seconds) printf(" --seconds %d", info->seconds);
    237 	if (info->check_set & XT_RECENT_REAP)
    238 		printf(" --reap");
    239 	if(info->hit_count) printf(" --hitcount %d", info->hit_count);
    240 	if (info->check_set & XT_RECENT_TTL)
    241 		printf(" --rttl");
    242 	if(info->name) printf(" --name %s",info->name);
    243 
    244 	switch(family) {
    245 	case NFPROTO_IPV4:
    246 		printf(" --mask %s",
    247 			xtables_ipaddr_to_numeric(&info->mask.in));
    248 		break;
    249 	case NFPROTO_IPV6:
    250 		printf(" --mask %s",
    251 			xtables_ip6addr_to_numeric(&info->mask.in6));
    252 		break;
    253 	}
    254 
    255 	if (info->side == XT_RECENT_SOURCE)
    256 		printf(" --rsource");
    257 	if (info->side == XT_RECENT_DEST)
    258 		printf(" --rdest");
    259 }
    260 
    261 static void recent_init_v0(struct xt_entry_match *match)
    262 {
    263 	recent_init(match, XT_RECENT_REV_0);
    264 }
    265 
    266 static void recent_init_v1(struct xt_entry_match *match)
    267 {
    268 	recent_init(match, XT_RECENT_REV_1);
    269 }
    270 
    271 static void recent_save_v0(const void *ip, const struct xt_entry_match *match)
    272 {
    273 	recent_save(ip, match, NFPROTO_UNSPEC);
    274 }
    275 
    276 static void recent_save_v4(const void *ip, const struct xt_entry_match *match)
    277 {
    278 	recent_save(ip, match, NFPROTO_IPV4);
    279 }
    280 
    281 static void recent_save_v6(const void *ip, const struct xt_entry_match *match)
    282 {
    283 	recent_save(ip, match, NFPROTO_IPV6);
    284 }
    285 
    286 static void recent_print_v0(const void *ip, const struct xt_entry_match *match,
    287 			    int numeric)
    288 {
    289 	recent_print(ip, match, NFPROTO_UNSPEC);
    290 }
    291 
    292 static void recent_print_v4(const void *ip, const struct xt_entry_match *match,
    293                          int numeric)
    294 {
    295 	recent_print(ip, match, NFPROTO_IPV4);
    296 }
    297 
    298 static void recent_print_v6(const void *ip, const struct xt_entry_match *match,
    299                          int numeric)
    300 {
    301 	recent_print(ip, match, NFPROTO_IPV6);
    302 }
    303 
    304 static struct xtables_match recent_mt_reg[] = {
    305 	{
    306 		.name          = "recent",
    307 		.version       = XTABLES_VERSION,
    308 		.revision      = 0,
    309 		.family        = NFPROTO_UNSPEC,
    310 		.size          = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
    311 		.userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
    312 		.help          = recent_help,
    313 		.init          = recent_init_v0,
    314 		.x6_parse      = recent_parse,
    315 		.x6_fcheck     = recent_check,
    316 		.print         = recent_print_v0,
    317 		.save          = recent_save_v0,
    318 		.x6_options    = recent_opts_v0,
    319 	},
    320 	{
    321 		.name          = "recent",
    322 		.version       = XTABLES_VERSION,
    323 		.revision      = 1,
    324 		.family        = NFPROTO_IPV4,
    325 		.size          = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)),
    326 		.userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)),
    327 		.help          = recent_help,
    328 		.init          = recent_init_v1,
    329 		.x6_parse      = recent_parse,
    330 		.x6_fcheck     = recent_check,
    331 		.print         = recent_print_v4,
    332 		.save          = recent_save_v4,
    333 		.x6_options    = recent_opts_v1,
    334 	},
    335 	{
    336 		.name          = "recent",
    337 		.version       = XTABLES_VERSION,
    338 		.revision      = 1,
    339 		.family        = NFPROTO_IPV6,
    340 		.size          = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)),
    341 		.userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)),
    342 		.help          = recent_help,
    343 		.init          = recent_init_v1,
    344 		.x6_parse      = recent_parse,
    345 		.x6_fcheck     = recent_check,
    346 		.print         = recent_print_v6,
    347 		.save          = recent_save_v6,
    348 		.x6_options    = recent_opts_v1,
    349 	},
    350 };
    351 
    352 void _init(void)
    353 {
    354 	xtables_register_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg));
    355 }
    356