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