libxt_limit.c revision 2c69b55e55f2efc5a334b87ccdceaa9de0ecb658
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Shared library add-on to iptables to add limit support. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr> 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Hervé Eychenne <rv@wallfire.org> 568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) */ 668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h> 968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include <stdlib.h> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <getopt.h> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <xtables.h> 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stddef.h> 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <linux/netfilter/x_tables.h> 1468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)/* For 64bit kernel / 32bit userspace */ 1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <linux/netfilter/xt_limit.h> 1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define XT_LIMIT_AVG "3/hour" 1868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#define XT_LIMIT_BURST 5 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)static void limit_help(void) 2158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles){ 2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) printf( 2368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)"limit match options:\n" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"--limit avg max average match rate: default "XT_LIMIT_AVG"\n" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)" [Packets per second unless followed by \n" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)" /sec /minute /hour /day postfixes]\n" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"--limit-burst number number to match in a burst, default %u\n", 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XT_LIMIT_BURST); 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)static const struct option limit_opts[] = { 32 { "limit", 1, NULL, '%' }, 33 { "limit-burst", 1, NULL, '$' }, 34 { .name = NULL } 35}; 36 37static 38int parse_rate(const char *rate, u_int32_t *val) 39{ 40 const char *delim; 41 u_int32_t r; 42 u_int32_t mult = 1; /* Seconds by default. */ 43 44 delim = strchr(rate, '/'); 45 if (delim) { 46 if (strlen(delim+1) == 0) 47 return 0; 48 49 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0) 50 mult = 1; 51 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0) 52 mult = 60; 53 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0) 54 mult = 60*60; 55 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0) 56 mult = 24*60*60; 57 else 58 return 0; 59 } 60 r = atoi(rate); 61 if (!r) 62 return 0; 63 64 /* This would get mapped to infinite (1/day is minimum they 65 can specify, so we're ok at that end). */ 66 if (r / mult > XT_LIMIT_SCALE) 67 xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate); 68 69 *val = XT_LIMIT_SCALE * mult / r; 70 return 1; 71} 72 73static void limit_init(struct xt_entry_match *m) 74{ 75 struct xt_rateinfo *r = (struct xt_rateinfo *)m->data; 76 77 parse_rate(XT_LIMIT_AVG, &r->avg); 78 r->burst = XT_LIMIT_BURST; 79 80} 81 82/* FIXME: handle overflow: 83 if (r->avg*r->burst/r->burst != r->avg) 84 xtables_error(PARAMETER_PROBLEM, 85 "Sorry: burst too large for that avg rate.\n"); 86*/ 87 88static int 89limit_parse(int c, char **argv, int invert, unsigned int *flags, 90 const void *entry, struct xt_entry_match **match) 91{ 92 struct xt_rateinfo *r = (struct xt_rateinfo *)(*match)->data; 93 unsigned int num; 94 95 switch(c) { 96 case '%': 97 if (xtables_check_inverse(argv[optind-1], &invert, &optind, 0)) break; 98 if (!parse_rate(optarg, &r->avg)) 99 xtables_error(PARAMETER_PROBLEM, 100 "bad rate `%s'", optarg); 101 break; 102 103 case '$': 104 if (xtables_check_inverse(argv[optind-1], &invert, &optind, 0)) break; 105 if (!xtables_strtoui(optarg, NULL, &num, 0, 10000)) 106 xtables_error(PARAMETER_PROBLEM, 107 "bad --limit-burst `%s'", optarg); 108 r->burst = num; 109 break; 110 111 default: 112 return 0; 113 } 114 115 if (invert) 116 xtables_error(PARAMETER_PROBLEM, 117 "limit does not support invert"); 118 119 return 1; 120} 121 122static const struct rates 123{ 124 const char *name; 125 u_int32_t mult; 126} rates[] = { { "day", XT_LIMIT_SCALE*24*60*60 }, 127 { "hour", XT_LIMIT_SCALE*60*60 }, 128 { "min", XT_LIMIT_SCALE*60 }, 129 { "sec", XT_LIMIT_SCALE } }; 130 131static void print_rate(u_int32_t period) 132{ 133 unsigned int i; 134 135 for (i = 1; i < ARRAY_SIZE(rates); ++i) 136 if (period > rates[i].mult 137 || rates[i].mult/period < rates[i].mult%period) 138 break; 139 140 printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name); 141} 142 143static void 144limit_print(const void *ip, const struct xt_entry_match *match, int numeric) 145{ 146 const struct xt_rateinfo *r = (const void *)match->data; 147 printf("limit: avg "); print_rate(r->avg); 148 printf("burst %u ", r->burst); 149} 150 151static void limit_save(const void *ip, const struct xt_entry_match *match) 152{ 153 const struct xt_rateinfo *r = (const void *)match->data; 154 155 printf("--limit "); print_rate(r->avg); 156 if (r->burst != XT_LIMIT_BURST) 157 printf("--limit-burst %u ", r->burst); 158} 159 160static struct xtables_match limit_match = { 161 .family = AF_UNSPEC, 162 .name = "limit", 163 .version = XTABLES_VERSION, 164 .size = XT_ALIGN(sizeof(struct xt_rateinfo)), 165 .userspacesize = offsetof(struct xt_rateinfo, prev), 166 .help = limit_help, 167 .init = limit_init, 168 .parse = limit_parse, 169 .print = limit_print, 170 .save = limit_save, 171 .extra_opts = limit_opts, 172}; 173 174void _init(void) 175{ 176 xtables_register_match(&limit_match); 177} 178