1#include <stdbool.h> 2#include <stdio.h> 3#include <string.h> 4#include <xtables.h> 5#include <linux/netfilter/xt_recent.h> 6 7enum { 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 26static 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 49static 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 74static 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 85static 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 123static 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 131static 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 159static 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 185static 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 200void _init(void) 201{ 202 xtables_register_match(&recent_mt_reg); 203} 204