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