1/* Shared library add-on to iptables to add recent matching support. */ 2#include <stdio.h> 3#include <netdb.h> 4#include <string.h> 5#include <stdlib.h> 6#include <getopt.h> 7 8#include <ip6tables.h> 9#include <linux/netfilter_ipv6/ip6_tables.h> 10#include <linux/netfilter/xt_recent.h> 11 12#ifndef XTABLES_VERSION 13#define XTABLES_VERSION IPTABLES_VERSION 14#endif 15 16#ifdef IPT_LIB_DIR 17#define xtables_target ip6tables_target 18#define xtables_register_target register_target6 19#endif 20 21/* Need these in order to not fail when compiling against an older kernel. */ 22#ifndef RECENT_NAME 23#define RECENT_NAME "ip6t_recent" 24#endif /* RECENT_NAME */ 25 26#ifndef RECENT_VER 27#define RECENT_VER "unknown" 28#endif /* RECENT_VER */ 29 30/* Options for this module */ 31static struct option opts[] = { 32 { .name = "set", .has_arg = 0, .flag = 0, .val = 201 }, 33 { .name = "rcheck", .has_arg = 0, .flag = 0, .val = 202 }, 34 { .name = "update", .has_arg = 0, .flag = 0, .val = 203 }, 35 { .name = "seconds", .has_arg = 1, .flag = 0, .val = 204 }, 36 { .name = "hitcount", .has_arg = 1, .flag = 0, .val = 205 }, 37 { .name = "remove", .has_arg = 0, .flag = 0, .val = 206 }, 38 { .name = "rttl", .has_arg = 0, .flag = 0, .val = 207 }, 39 { .name = "name", .has_arg = 1, .flag = 0, .val = 208 }, 40 { .name = "rsource", .has_arg = 0, .flag = 0, .val = 209 }, 41 { .name = "rdest", .has_arg = 0, .flag = 0, .val = 210 }, 42 { .name = 0, .has_arg = 0, .flag = 0, .val = 0 } 43}; 44 45/* Function which prints out usage message. */ 46static void 47help(void) 48{ 49 printf( 50"recent v%s options:\n" 51"[!] --set Add source address to list, always matches.\n" 52"[!] --rcheck Match if source address in list.\n" 53"[!] --update Match if source address in list, also update last-seen time.\n" 54"[!] --remove Match if source address in list, also removes that address from list.\n" 55" --seconds seconds For check and update commands above.\n" 56" Specifies that the match will only occur if source address last seen within\n" 57" the last 'seconds' seconds.\n" 58" --hitcount hits For check and update commands above.\n" 59" Specifies that the match will only occur if source address seen hits times.\n" 60" May be used in conjunction with the seconds option.\n" 61" --rttl For check and update commands above.\n" 62" Specifies that the match will only occur if the source address and the TTL\n" 63" match between this packet and the one which was set.\n" 64" Useful if you have problems with people spoofing their source address in order\n" 65" to DoS you via this module.\n" 66" --name name Name of the recent list to be used. DEFAULT used if none given.\n" 67" --rsource Match/Save the source address of each packet in the recent list table (default).\n" 68" --rdest Match/Save the destination address of each packet in the recent list table.\n" 69RECENT_NAME " " RECENT_VER ": Stephen Frost <sfrost@snowman.net>. http://snowman.net/projects/ipt_recent/\n" 70, 71IPTABLES_VERSION); 72 73} 74 75/* Initialize the match. */ 76static void 77init(struct ip6t_entry_match *match, unsigned int *nfcache) 78{ 79 struct xt_recent_mtinfo *info = (struct xt_recent_mtinfo *)(match)->data; 80 81 82 strncpy(info->name,"DEFAULT",XT_RECENT_NAME_LEN); 83 /* eventhough XT_RECENT_NAME_LEN is currently defined as 200, 84 * better be safe, than sorry */ 85 info->name[XT_RECENT_NAME_LEN-1] = '\0'; 86 info->side = XT_RECENT_SOURCE; 87} 88 89/* Function which parses command options; returns true if it 90 ate an option */ 91static int 92parse(int c, char **argv, int invert, unsigned int *flags, 93 const struct ip6t_entry *entry, 94 unsigned int *nfcache, 95 struct ip6t_entry_match **match) 96{ 97 struct xt_recent_mtinfo *info = (struct xt_recent_mtinfo *)(*match)->data; 98 switch (c) { 99 case 201: 100 if (*flags) exit_error(PARAMETER_PROBLEM, 101 "recent: only one of `--set', `--rcheck' " 102 "`--update' or `--remove' may be set"); 103 check_inverse(optarg, &invert, &optind, 0); 104 info->check_set |= XT_RECENT_SET; 105 if (invert) info->invert = 1; 106 *flags = 1; 107 break; 108 109 case 202: 110 if (*flags) exit_error(PARAMETER_PROBLEM, 111 "recent: only one of `--set', `--rcheck' " 112 "`--update' or `--remove' may be set"); 113 check_inverse(optarg, &invert, &optind, 0); 114 info->check_set |= XT_RECENT_CHECK; 115 if(invert) info->invert = 1; 116 *flags = 1; 117 break; 118 119 case 203: 120 if (*flags) exit_error(PARAMETER_PROBLEM, 121 "recent: only one of `--set', `--rcheck' " 122 "`--update' or `--remove' may be set"); 123 check_inverse(optarg, &invert, &optind, 0); 124 info->check_set |= XT_RECENT_UPDATE; 125 if (invert) info->invert = 1; 126 *flags = 1; 127 break; 128 129 case 206: 130 if (*flags) exit_error(PARAMETER_PROBLEM, 131 "recent: only one of `--set', `--rcheck' " 132 "`--update' or `--remove' may be set"); 133 check_inverse(optarg, &invert, &optind, 0); 134 info->check_set |= XT_RECENT_REMOVE; 135 if (invert) info->invert = 1; 136 *flags = 1; 137 break; 138 139 case 204: 140 info->seconds = atoi(optarg); 141 break; 142 143 case 205: 144 info->hit_count = atoi(optarg); 145 break; 146 147 case 207: 148 info->check_set |= XT_RECENT_TTL; 149 break; 150 151 case 208: 152 strncpy(info->name,optarg,XT_RECENT_NAME_LEN); 153 info->name[XT_RECENT_NAME_LEN-1] = '\0'; 154 break; 155 156 case 209: 157 info->side = XT_RECENT_SOURCE; 158 break; 159 160 case 210: 161 info->side = XT_RECENT_DEST; 162 break; 163 164 default: 165 return 0; 166 } 167 168 return 1; 169} 170 171/* Final check; must have specified a specific option. */ 172static void 173final_check(unsigned int flags) 174{ 175 if (!flags) 176 exit_error(PARAMETER_PROBLEM, 177 "recent: you must specify one of `--set', `--rcheck' " 178 "`--update' or `--remove'"); 179} 180 181/* Prints out the matchinfo. */ 182static void 183print(const struct ip6t_ip6 *ip, 184 const struct ip6t_entry_match *match, 185 int numeric) 186{ 187 struct xt_recent_mtinfo *info = (struct xt_recent_mtinfo *)match->data; 188 189 if (info->invert) 190 fputc('!', stdout); 191 192 printf("recent: "); 193 if(info->check_set & XT_RECENT_SET) printf("SET "); 194 if(info->check_set & XT_RECENT_CHECK) printf("CHECK "); 195 if(info->check_set & XT_RECENT_UPDATE) printf("UPDATE "); 196 if(info->check_set & XT_RECENT_REMOVE) printf("REMOVE "); 197 if(info->seconds) printf("seconds: %d ",info->seconds); 198 if(info->hit_count) printf("hit_count: %d ",info->hit_count); 199 if(info->check_set & XT_RECENT_TTL) printf("TTL-Match "); 200 if(info->name) printf("name: %s ",info->name); 201 if(info->side == XT_RECENT_SOURCE) printf("side: source "); 202 if(info->side == XT_RECENT_DEST) printf("side: dest"); 203} 204 205/* Saves the union ip6t_matchinfo in parsable form to stdout. */ 206static void 207save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) 208{ 209 struct xt_recent_mtinfo *info = (struct xt_recent_mtinfo *)match->data; 210 211 if (info->invert) 212 printf("! "); 213 214 if(info->check_set & XT_RECENT_SET) printf("--set "); 215 if(info->check_set & XT_RECENT_CHECK) printf("--rcheck "); 216 if(info->check_set & XT_RECENT_UPDATE) printf("--update "); 217 if(info->check_set & XT_RECENT_REMOVE) printf("--remove "); 218 if(info->seconds) printf("--seconds %d ",info->seconds); 219 if(info->hit_count) printf("--hitcount %d ",info->hit_count); 220 if(info->check_set & XT_RECENT_TTL) printf("--rttl "); 221 if(info->name) printf("--name %s ",info->name); 222 if(info->side == XT_RECENT_SOURCE) printf("--rsource "); 223 if(info->side == XT_RECENT_DEST) printf("--rdest "); 224} 225 226/* Structure for iptables to use to communicate with module */ 227static struct ip6tables_match recent = { 228 .next = NULL, 229 .name = "recent", 230 .version = XTABLES_VERSION, 231 .size = IP6T_ALIGN(sizeof(struct xt_recent_mtinfo)), 232 .userspacesize = IP6T_ALIGN(sizeof(struct xt_recent_mtinfo)), 233 .help = &help, 234 .init = &init, 235 .parse = &parse, 236 .final_check = &final_check, 237 .print = &print, 238 .save = &save, 239 .extra_opts = opts, 240}; 241 242void _init(void) 243{ 244 register_match6(&recent); 245} 246