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#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 19enum { 20 O_LIMIT = 0, 21 O_BURST, 22}; 23 24static 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", 32XT_LIMIT_BURST); 33} 34 35static 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 43static 44int 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 80static 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 95static 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 112static 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 121static 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 138static void 139limit_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 146static 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 155static 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 169void _init(void) 170{ 171 xtables_register_match(&limit_match); 172} 173