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 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 (at) snowman.net>. http://snowman.net/projects/ipt_recent/\n"); 72 } 73 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 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 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 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 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 200 void _init(void) 201 { 202 xtables_register_match(&recent_mt_reg); 203 } 204