libxt_limit.c revision 0e2abed11985e16215559cefd90625f99317b96c
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 "../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 22help(void) 23{ 24 printf( 25"limit v%s 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" 30"\n", IPTABLES_VERSION, XT_LIMIT_BURST); 31} 32 33static const struct option opts[] = { 34 { "limit", 1, NULL, '%' }, 35 { "limit-burst", 1, NULL, '$' }, 36 { } 37}; 38 39static 40int parse_rate(const char *rate, u_int32_t *val) 41{ 42 const char *delim; 43 u_int32_t r; 44 u_int32_t mult = 1; /* Seconds by default. */ 45 46 delim = strchr(rate, '/'); 47 if (delim) { 48 if (strlen(delim+1) == 0) 49 return 0; 50 51 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0) 52 mult = 1; 53 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0) 54 mult = 60; 55 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0) 56 mult = 60*60; 57 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0) 58 mult = 24*60*60; 59 else 60 return 0; 61 } 62 r = atoi(rate); 63 if (!r) 64 return 0; 65 66 /* This would get mapped to infinite (1/day is minimum they 67 can specify, so we're ok at that end). */ 68 if (r / mult > XT_LIMIT_SCALE) 69 exit_error(PARAMETER_PROBLEM, "Rate too fast `%s'\n", rate); 70 71 *val = XT_LIMIT_SCALE * mult / r; 72 return 1; 73} 74 75/* Initialize the match. */ 76static void 77init(struct xt_entry_match *m) 78{ 79 struct xt_rateinfo *r = (struct xt_rateinfo *)m->data; 80 81 parse_rate(XT_LIMIT_AVG, &r->avg); 82 r->burst = XT_LIMIT_BURST; 83 84} 85 86/* FIXME: handle overflow: 87 if (r->avg*r->burst/r->burst != r->avg) 88 exit_error(PARAMETER_PROBLEM, 89 "Sorry: burst too large for that avg rate.\n"); 90*/ 91 92/* Function which parses command options; returns true if it 93 ate an option */ 94static int 95parse(int c, char **argv, int invert, unsigned int *flags, 96 const void *entry, 97 struct xt_entry_match **match) 98{ 99 struct xt_rateinfo *r = (struct xt_rateinfo *)(*match)->data; 100 unsigned int num; 101 102 switch(c) { 103 case '%': 104 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break; 105 if (!parse_rate(optarg, &r->avg)) 106 exit_error(PARAMETER_PROBLEM, 107 "bad rate `%s'", optarg); 108 break; 109 110 case '$': 111 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break; 112 if (string_to_number(optarg, 0, 10000, &num) == -1) 113 exit_error(PARAMETER_PROBLEM, 114 "bad --limit-burst `%s'", optarg); 115 r->burst = num; 116 break; 117 118 default: 119 return 0; 120 } 121 122 if (invert) 123 exit_error(PARAMETER_PROBLEM, 124 "limit does not support invert"); 125 126 return 1; 127} 128 129static const struct rates 130{ 131 const char *name; 132 u_int32_t mult; 133} rates[] = { { "day", XT_LIMIT_SCALE*24*60*60 }, 134 { "hour", XT_LIMIT_SCALE*60*60 }, 135 { "min", XT_LIMIT_SCALE*60 }, 136 { "sec", XT_LIMIT_SCALE } }; 137 138static void print_rate(u_int32_t period) 139{ 140 unsigned int i; 141 142 for (i = 1; i < sizeof(rates)/sizeof(struct rates); i++) { 143 if (period > rates[i].mult 144 || rates[i].mult/period < rates[i].mult%period) 145 break; 146 } 147 148 printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name); 149} 150 151/* Prints out the matchinfo. */ 152static void 153print(const void *ip, 154 const struct xt_entry_match *match, 155 int numeric) 156{ 157 struct xt_rateinfo *r = (struct xt_rateinfo *)match->data; 158 printf("limit: avg "); print_rate(r->avg); 159 printf("burst %u ", r->burst); 160} 161 162/* FIXME: Make minimalist: only print rate if not default --RR */ 163static void save(const void *ip, const struct xt_entry_match *match) 164{ 165 struct xt_rateinfo *r = (struct xt_rateinfo *)match->data; 166 167 printf("--limit "); print_rate(r->avg); 168 if (r->burst != XT_LIMIT_BURST) 169 printf("--limit-burst %u ", r->burst); 170} 171 172static struct xtables_match limit = { 173 .family = AF_INET, 174 .name = "limit", 175 .version = IPTABLES_VERSION, 176 .size = XT_ALIGN(sizeof(struct xt_rateinfo)), 177 .userspacesize = offsetof(struct xt_rateinfo, prev), 178 .help = &help, 179 .init = &init, 180 .parse = &parse, 181 .print = &print, 182 .save = &save, 183 .extra_opts = opts 184}; 185 186static struct xtables_match limit6 = { 187 .family = AF_INET6, 188 .name = "limit", 189 .version = IPTABLES_VERSION, 190 .size = XT_ALIGN(sizeof(struct xt_rateinfo)), 191 .userspacesize = offsetof(struct xt_rateinfo, prev), 192 .help = &help, 193 .init = &init, 194 .parse = &parse, 195 .print = &print, 196 .save = &save, 197 .extra_opts = opts 198}; 199 200void _init(void) 201{ 202 xtables_register_match(&limit); 203 xtables_register_match(&limit6); 204} 205