libxt_limit.c revision 9d69da4bdb1d546218d168b72f12ac8aa042e3d8
1/* Shared library add-on to iptables to add limit support. 2 * 3 * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr> 4 * Hervé Eychenne <rv@wallfire.org> 5 */ 6#include <math.h> 7#include <stdio.h> 8#include <string.h> 9#include <stdlib.h> 10#include <xtables.h> 11#include <linux/netfilter/x_tables.h> 12#include <linux/netfilter/xt_limit.h> 13 14#define XT_LIMIT_AVG "3/hour" 15#define XT_LIMIT_BURST 5 16 17enum { 18 O_LIMIT = 0, 19 O_BURST, 20}; 21 22static void limit_help(void) 23{ 24 printf( 25"limit match options:\n" 26"--limit avg max average match rate: default "XT_LIMIT_AVG"\n" 27" [Packets per second unless followed by \n" 28" /sec /minute /hour /day postfixes]\n" 29"--limit-burst number number to match in a burst, default %u\n", 30XT_LIMIT_BURST); 31} 32 33static const struct xt_option_entry limit_opts[] = { 34 {.name = "limit", .id = O_LIMIT, .type = XTTYPE_STRING}, 35 {.name = "limit-burst", .id = O_BURST, .type = XTTYPE_UINT32, 36 .flags = XTOPT_PUT, XTOPT_POINTER(struct xt_rateinfo, burst), 37 .min = 0, .max = 10000}, 38 XTOPT_TABLEEND, 39}; 40 41static 42int parse_rate(const char *rate, uint32_t *val) 43{ 44 const char *delim; 45 uint32_t r; 46 uint32_t mult = 1; /* Seconds by default. */ 47 48 delim = strchr(rate, '/'); 49 if (delim) { 50 if (strlen(delim+1) == 0) 51 return 0; 52 53 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0) 54 mult = 1; 55 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0) 56 mult = 60; 57 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0) 58 mult = 60*60; 59 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0) 60 mult = 24*60*60; 61 else 62 return 0; 63 } 64 r = atoi(rate); 65 if (!r) 66 return 0; 67 68 *val = XT_LIMIT_SCALE * mult / r; 69 if (*val == 0) 70 /* 71 * The rate maps to infinity. (1/day is the minimum they can 72 * specify, so we are ok at that end). 73 */ 74 xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate); 75 return 1; 76} 77 78static void limit_init(struct xt_entry_match *m) 79{ 80 struct xt_rateinfo *r = (struct xt_rateinfo *)m->data; 81 82 parse_rate(XT_LIMIT_AVG, &r->avg); 83 r->burst = XT_LIMIT_BURST; 84 85} 86 87/* FIXME: handle overflow: 88 if (r->avg*r->burst/r->burst != r->avg) 89 xtables_error(PARAMETER_PROBLEM, 90 "Sorry: burst too large for that avg rate.\n"); 91*/ 92 93static void limit_parse(struct xt_option_call *cb) 94{ 95 struct xt_rateinfo *r = cb->data; 96 97 xtables_option_parse(cb); 98 switch (cb->entry->id) { 99 case O_LIMIT: 100 if (!parse_rate(cb->arg, &r->avg)) 101 xtables_error(PARAMETER_PROBLEM, 102 "bad rate \"%s\"'", cb->arg); 103 break; 104 } 105 if (cb->invert) 106 xtables_error(PARAMETER_PROBLEM, 107 "limit does not support invert"); 108} 109 110static const struct rates 111{ 112 const char *name; 113 uint32_t mult; 114} rates[] = { { "day", XT_LIMIT_SCALE*24*60*60 }, 115 { "hour", XT_LIMIT_SCALE*60*60 }, 116 { "min", XT_LIMIT_SCALE*60 }, 117 { "sec", XT_LIMIT_SCALE } }; 118 119static void print_rate(uint32_t period) 120{ 121 unsigned int i; 122 123 if (period == 0) { 124 printf(" %f", INFINITY); 125 return; 126 } 127 128 for (i = 1; i < ARRAY_SIZE(rates); ++i) 129 if (period > rates[i].mult 130 || rates[i].mult/period < rates[i].mult%period) 131 break; 132 133 printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name); 134} 135 136static void 137limit_print(const void *ip, const struct xt_entry_match *match, int numeric) 138{ 139 const struct xt_rateinfo *r = (const void *)match->data; 140 printf(" limit: avg"); print_rate(r->avg); 141 printf(" burst %u", r->burst); 142} 143 144static void limit_save(const void *ip, const struct xt_entry_match *match) 145{ 146 const struct xt_rateinfo *r = (const void *)match->data; 147 148 printf(" --limit"); print_rate(r->avg); 149 if (r->burst != XT_LIMIT_BURST) 150 printf(" --limit-burst %u", r->burst); 151} 152 153static struct xtables_match limit_match = { 154 .family = NFPROTO_UNSPEC, 155 .name = "limit", 156 .version = XTABLES_VERSION, 157 .size = XT_ALIGN(sizeof(struct xt_rateinfo)), 158 .userspacesize = offsetof(struct xt_rateinfo, prev), 159 .help = limit_help, 160 .init = limit_init, 161 .x6_parse = limit_parse, 162 .print = limit_print, 163 .save = limit_save, 164 .x6_options = limit_opts, 165}; 166 167void _init(void) 168{ 169 xtables_register_match(&limit_match); 170} 171