libxt_limit.c revision a2a7f2b531cc582ab6cc3c2b73715ed1d58b9eab
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 7#include <stdio.h> 8#include <string.h> 9#include <stdlib.h> 10#include <getopt.h> 11#include <xtables.h> 12#include <stddef.h> 13#include <linux/netfilter/x_tables.h> 14/* For 64bit kernel / 32bit userspace */ 15#include <linux/netfilter/xt_limit.h> 16 17#define XT_LIMIT_AVG "3/hour" 18#define XT_LIMIT_BURST 5 19 20/* Function which prints out usage message. */ 21static void limit_help(void) 22{ 23 printf( 24"limit match options:\n" 25"--limit avg max average match rate: default "XT_LIMIT_AVG"\n" 26" [Packets per second unless followed by \n" 27" /sec /minute /hour /day postfixes]\n" 28"--limit-burst number number to match in a burst, default %u\n", 29XT_LIMIT_BURST); 30} 31 32static const struct option limit_opts[] = { 33 { "limit", 1, NULL, '%' }, 34 { "limit-burst", 1, NULL, '$' }, 35 { .name = NULL } 36}; 37 38static 39int parse_rate(const char *rate, u_int32_t *val) 40{ 41 const char *delim; 42 u_int32_t r; 43 u_int32_t mult = 1; /* Seconds by default. */ 44 45 delim = strchr(rate, '/'); 46 if (delim) { 47 if (strlen(delim+1) == 0) 48 return 0; 49 50 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0) 51 mult = 1; 52 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0) 53 mult = 60; 54 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0) 55 mult = 60*60; 56 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0) 57 mult = 24*60*60; 58 else 59 return 0; 60 } 61 r = atoi(rate); 62 if (!r) 63 return 0; 64 65 /* This would get mapped to infinite (1/day is minimum they 66 can specify, so we're ok at that end). */ 67 if (r / mult > XT_LIMIT_SCALE) 68 exit_error(PARAMETER_PROBLEM, "Rate too fast `%s'\n", rate); 69 70 *val = XT_LIMIT_SCALE * mult / r; 71 return 1; 72} 73 74/* Initialize the match. */ 75static void limit_init(struct xt_entry_match *m) 76{ 77 struct xt_rateinfo *r = (struct xt_rateinfo *)m->data; 78 79 parse_rate(XT_LIMIT_AVG, &r->avg); 80 r->burst = XT_LIMIT_BURST; 81 82} 83 84/* FIXME: handle overflow: 85 if (r->avg*r->burst/r->burst != r->avg) 86 exit_error(PARAMETER_PROBLEM, 87 "Sorry: burst too large for that avg rate.\n"); 88*/ 89 90/* Function which parses command options; returns true if it 91 ate an option */ 92static int 93limit_parse(int c, char **argv, int invert, unsigned int *flags, 94 const void *entry, struct xt_entry_match **match) 95{ 96 struct xt_rateinfo *r = (struct xt_rateinfo *)(*match)->data; 97 unsigned int num; 98 99 switch(c) { 100 case '%': 101 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break; 102 if (!parse_rate(optarg, &r->avg)) 103 exit_error(PARAMETER_PROBLEM, 104 "bad rate `%s'", optarg); 105 break; 106 107 case '$': 108 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break; 109 if (string_to_number(optarg, 0, 10000, &num) == -1) 110 exit_error(PARAMETER_PROBLEM, 111 "bad --limit-burst `%s'", optarg); 112 r->burst = num; 113 break; 114 115 default: 116 return 0; 117 } 118 119 if (invert) 120 exit_error(PARAMETER_PROBLEM, 121 "limit does not support invert"); 122 123 return 1; 124} 125 126static const struct rates 127{ 128 const char *name; 129 u_int32_t mult; 130} rates[] = { { "day", XT_LIMIT_SCALE*24*60*60 }, 131 { "hour", XT_LIMIT_SCALE*60*60 }, 132 { "min", XT_LIMIT_SCALE*60 }, 133 { "sec", XT_LIMIT_SCALE } }; 134 135static void print_rate(u_int32_t period) 136{ 137 unsigned int i; 138 139 for (i = 1; i < sizeof(rates)/sizeof(struct rates); i++) { 140 if (period > rates[i].mult 141 || rates[i].mult/period < rates[i].mult%period) 142 break; 143 } 144 145 printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name); 146} 147 148/* Prints out the matchinfo. */ 149static void 150limit_print(const void *ip, const struct xt_entry_match *match, int numeric) 151{ 152 struct xt_rateinfo *r = (struct xt_rateinfo *)match->data; 153 printf("limit: avg "); print_rate(r->avg); 154 printf("burst %u ", r->burst); 155} 156 157/* FIXME: Make minimalist: only print rate if not default --RR */ 158static void limit_save(const void *ip, const struct xt_entry_match *match) 159{ 160 struct xt_rateinfo *r = (struct xt_rateinfo *)match->data; 161 162 printf("--limit "); print_rate(r->avg); 163 if (r->burst != XT_LIMIT_BURST) 164 printf("--limit-burst %u ", r->burst); 165} 166 167static struct xtables_match limit_match = { 168 .family = AF_UNSPEC, 169 .name = "limit", 170 .version = XTABLES_VERSION, 171 .size = XT_ALIGN(sizeof(struct xt_rateinfo)), 172 .userspacesize = offsetof(struct xt_rateinfo, prev), 173 .help = limit_help, 174 .init = limit_init, 175 .parse = limit_parse, 176 .print = limit_print, 177 .save = limit_save, 178 .extra_opts = limit_opts, 179}; 180 181void _init(void) 182{ 183 xtables_register_match(&limit_match); 184} 185