1 #include <stdbool.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include <stdlib.h> 5 #include <stddef.h> 6 #include <getopt.h> 7 8 #include <xtables.h> 9 #include <linux/netfilter/xt_rateest.h> 10 11 /* Ugly hack to pass info to final_check function. We should fix the API */ 12 static struct xt_rateest_match_info *rateest_info; 13 14 static void rateest_help(void) 15 { 16 printf( 17 "rateest match options:\n" 18 " --rateest1 name Rate estimator name\n" 19 " --rateest2 name Rate estimator name\n" 20 " --rateest-delta Compare difference(s) to given rate(s)\n" 21 " --rateest-bps1 [bps] Compare bps\n" 22 " --rateest-pps1 [pps] Compare pps\n" 23 " --rateest-bps2 [bps] Compare bps\n" 24 " --rateest-pps2 [pps] Compare pps\n" 25 " [!] --rateest-lt Match if rate is less than given rate/estimator\n" 26 " [!] --rateest-gt Match if rate is greater than given rate/estimator\n" 27 " [!] --rateest-eq Match if rate is equal to given rate/estimator\n"); 28 } 29 30 enum rateest_options { 31 OPT_RATEEST1, 32 OPT_RATEEST2, 33 OPT_RATEEST_BPS1, 34 OPT_RATEEST_PPS1, 35 OPT_RATEEST_BPS2, 36 OPT_RATEEST_PPS2, 37 OPT_RATEEST_DELTA, 38 OPT_RATEEST_LT, 39 OPT_RATEEST_GT, 40 OPT_RATEEST_EQ, 41 }; 42 43 static const struct option rateest_opts[] = { 44 {.name = "rateest1", .has_arg = true, .val = OPT_RATEEST1}, 45 {.name = "rateest", .has_arg = true, .val = OPT_RATEEST1}, /* alias for absolute mode */ 46 {.name = "rateest2", .has_arg = true, .val = OPT_RATEEST2}, 47 {.name = "rateest-bps1", .has_arg = false, .val = OPT_RATEEST_BPS1}, 48 {.name = "rateest-pps1", .has_arg = false, .val = OPT_RATEEST_PPS1}, 49 {.name = "rateest-bps2", .has_arg = false, .val = OPT_RATEEST_BPS2}, 50 {.name = "rateest-pps2", .has_arg = false, .val = OPT_RATEEST_PPS2}, 51 {.name = "rateest-bps", .has_arg = false, .val = OPT_RATEEST_BPS2}, /* alias for absolute mode */ 52 {.name = "rateest-pps", .has_arg = false, .val = OPT_RATEEST_PPS2}, /* alias for absolute mode */ 53 {.name = "rateest-delta", .has_arg = false, .val = OPT_RATEEST_DELTA}, 54 {.name = "rateest-lt", .has_arg = false, .val = OPT_RATEEST_LT}, 55 {.name = "rateest-gt", .has_arg = false, .val = OPT_RATEEST_GT}, 56 {.name = "rateest-eq", .has_arg = false, .val = OPT_RATEEST_EQ}, 57 XT_GETOPT_TABLEEND, 58 }; 59 60 /* Copied from iproute. See http://physics.nist.gov/cuu/Units/binary.html */ 61 static const struct rate_suffix { 62 const char *name; 63 double scale; 64 } suffixes[] = { 65 { "bit", 1. }, 66 { "Kibit", 1024. }, 67 { "kbit", 1000. }, 68 { "Mibit", 1024.*1024. }, 69 { "mbit", 1000000. }, 70 { "Gibit", 1024.*1024.*1024. }, 71 { "gbit", 1000000000. }, 72 { "Tibit", 1024.*1024.*1024.*1024. }, 73 { "tbit", 1000000000000. }, 74 { "Bps", 8. }, 75 { "KiBps", 8.*1024. }, 76 { "KBps", 8000. }, 77 { "MiBps", 8.*1024*1024. }, 78 { "MBps", 8000000. }, 79 { "GiBps", 8.*1024.*1024.*1024. }, 80 { "GBps", 8000000000. }, 81 { "TiBps", 8.*1024.*1024.*1024.*1024. }, 82 { "TBps", 8000000000000. }, 83 {NULL}, 84 }; 85 86 static int 87 rateest_get_rate(uint32_t *rate, const char *str) 88 { 89 char *p; 90 double bps = strtod(str, &p); 91 const struct rate_suffix *s; 92 93 if (p == str) 94 return -1; 95 96 if (*p == '\0') { 97 *rate = bps / 8.; /* assume bytes/sec */ 98 return 0; 99 } 100 101 for (s = suffixes; s->name; ++s) { 102 if (strcasecmp(s->name, p) == 0) { 103 *rate = (bps * s->scale) / 8.; 104 return 0; 105 } 106 } 107 108 return -1; 109 } 110 111 static int 112 rateest_parse(int c, char **argv, int invert, unsigned int *flags, 113 const void *entry, struct xt_entry_match **match) 114 { 115 struct xt_rateest_match_info *info = (void *)(*match)->data; 116 unsigned int val; 117 118 rateest_info = info; 119 120 switch (c) { 121 case OPT_RATEEST1: 122 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 123 if (invert) 124 xtables_error(PARAMETER_PROBLEM, 125 "rateest: rateest can't be inverted"); 126 127 if (*flags & (1 << c)) 128 xtables_error(PARAMETER_PROBLEM, 129 "rateest: can't specify --rateest1 twice"); 130 *flags |= 1 << c; 131 132 strncpy(info->name1, optarg, sizeof(info->name1) - 1); 133 break; 134 135 case OPT_RATEEST2: 136 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 137 if (invert) 138 xtables_error(PARAMETER_PROBLEM, 139 "rateest: rateest can't be inverted"); 140 141 if (*flags & (1 << c)) 142 xtables_error(PARAMETER_PROBLEM, 143 "rateest: can't specify --rateest2 twice"); 144 *flags |= 1 << c; 145 146 strncpy(info->name2, optarg, sizeof(info->name2) - 1); 147 info->flags |= XT_RATEEST_MATCH_REL; 148 break; 149 150 case OPT_RATEEST_BPS1: 151 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 152 if (invert) 153 xtables_error(PARAMETER_PROBLEM, 154 "rateest: rateest-bps can't be inverted"); 155 156 if (*flags & (1 << c)) 157 xtables_error(PARAMETER_PROBLEM, 158 "rateest: can't specify --rateest-bps1 twice"); 159 *flags |= 1 << c; 160 161 info->flags |= XT_RATEEST_MATCH_BPS; 162 163 /* The rate is optional and only required in absolute mode */ 164 if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!') 165 break; 166 167 if (rateest_get_rate(&info->bps1, argv[optind]) < 0) 168 xtables_error(PARAMETER_PROBLEM, 169 "rateest: could not parse rate `%s'", 170 argv[optind]); 171 optind++; 172 break; 173 174 case OPT_RATEEST_PPS1: 175 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 176 if (invert) 177 xtables_error(PARAMETER_PROBLEM, 178 "rateest: rateest-pps can't be inverted"); 179 180 if (*flags & (1 << c)) 181 xtables_error(PARAMETER_PROBLEM, 182 "rateest: can't specify --rateest-pps1 twice"); 183 *flags |= 1 << c; 184 185 info->flags |= XT_RATEEST_MATCH_PPS; 186 187 /* The rate is optional and only required in absolute mode */ 188 if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!') 189 break; 190 191 if (!xtables_strtoui(argv[optind], NULL, &val, 0, UINT32_MAX)) 192 xtables_error(PARAMETER_PROBLEM, 193 "rateest: could not parse pps `%s'", 194 argv[optind]); 195 info->pps1 = val; 196 optind++; 197 break; 198 199 case OPT_RATEEST_BPS2: 200 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 201 if (invert) 202 xtables_error(PARAMETER_PROBLEM, 203 "rateest: rateest-bps can't be inverted"); 204 205 if (*flags & (1 << c)) 206 xtables_error(PARAMETER_PROBLEM, 207 "rateest: can't specify --rateest-bps2 twice"); 208 *flags |= 1 << c; 209 210 info->flags |= XT_RATEEST_MATCH_BPS; 211 212 /* The rate is optional and only required in absolute mode */ 213 if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!') 214 break; 215 216 if (rateest_get_rate(&info->bps2, argv[optind]) < 0) 217 xtables_error(PARAMETER_PROBLEM, 218 "rateest: could not parse rate `%s'", 219 argv[optind]); 220 optind++; 221 break; 222 223 case OPT_RATEEST_PPS2: 224 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 225 if (invert) 226 xtables_error(PARAMETER_PROBLEM, 227 "rateest: rateest-pps can't be inverted"); 228 229 if (*flags & (1 << c)) 230 xtables_error(PARAMETER_PROBLEM, 231 "rateest: can't specify --rateest-pps2 twice"); 232 *flags |= 1 << c; 233 234 info->flags |= XT_RATEEST_MATCH_PPS; 235 236 /* The rate is optional and only required in absolute mode */ 237 if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!') 238 break; 239 240 if (!xtables_strtoui(argv[optind], NULL, &val, 0, UINT32_MAX)) 241 xtables_error(PARAMETER_PROBLEM, 242 "rateest: could not parse pps `%s'", 243 argv[optind]); 244 info->pps2 = val; 245 optind++; 246 break; 247 248 case OPT_RATEEST_DELTA: 249 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 250 if (invert) 251 xtables_error(PARAMETER_PROBLEM, 252 "rateest: rateest-delta can't be inverted"); 253 254 if (*flags & (1 << c)) 255 xtables_error(PARAMETER_PROBLEM, 256 "rateest: can't specify --rateest-delta twice"); 257 *flags |= 1 << c; 258 259 info->flags |= XT_RATEEST_MATCH_DELTA; 260 break; 261 262 case OPT_RATEEST_EQ: 263 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 264 265 if (*flags & (1 << c)) 266 xtables_error(PARAMETER_PROBLEM, 267 "rateest: can't specify lt/gt/eq twice"); 268 *flags |= 1 << c; 269 270 info->mode = XT_RATEEST_MATCH_EQ; 271 if (invert) 272 info->flags |= XT_RATEEST_MATCH_INVERT; 273 break; 274 275 case OPT_RATEEST_LT: 276 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 277 278 if (*flags & (1 << c)) 279 xtables_error(PARAMETER_PROBLEM, 280 "rateest: can't specify lt/gt/eq twice"); 281 *flags |= 1 << c; 282 283 info->mode = XT_RATEEST_MATCH_LT; 284 if (invert) 285 info->flags |= XT_RATEEST_MATCH_INVERT; 286 break; 287 288 case OPT_RATEEST_GT: 289 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 290 291 if (*flags & (1 << c)) 292 xtables_error(PARAMETER_PROBLEM, 293 "rateest: can't specify lt/gt/eq twice"); 294 *flags |= 1 << c; 295 296 info->mode = XT_RATEEST_MATCH_GT; 297 if (invert) 298 info->flags |= XT_RATEEST_MATCH_INVERT; 299 break; 300 } 301 302 return 1; 303 } 304 305 static void 306 rateest_final_check(unsigned int flags) 307 { 308 struct xt_rateest_match_info *info = rateest_info; 309 310 if (info == NULL) 311 xtables_error(PARAMETER_PROBLEM, "rateest match: " 312 "you need to specify some flags"); 313 if (!(info->flags & XT_RATEEST_MATCH_REL)) 314 info->flags |= XT_RATEEST_MATCH_ABS; 315 } 316 317 static void 318 rateest_print_rate(uint32_t rate, int numeric) 319 { 320 double tmp = (double)rate*8; 321 322 if (numeric) 323 printf(" %u", rate); 324 else if (tmp >= 1000.0*1000000.0) 325 printf(" %.0fMbit", tmp/1000000.0); 326 else if (tmp >= 1000.0 * 1000.0) 327 printf(" %.0fKbit", tmp/1000.0); 328 else 329 printf(" %.0fbit", tmp); 330 } 331 332 static void 333 rateest_print_mode(const struct xt_rateest_match_info *info, 334 const char *prefix) 335 { 336 if (info->flags & XT_RATEEST_MATCH_INVERT) 337 printf(" !"); 338 339 switch (info->mode) { 340 case XT_RATEEST_MATCH_EQ: 341 printf(" %seq", prefix); 342 break; 343 case XT_RATEEST_MATCH_LT: 344 printf(" %slt", prefix); 345 break; 346 case XT_RATEEST_MATCH_GT: 347 printf(" %sgt", prefix); 348 break; 349 default: 350 exit(1); 351 } 352 } 353 354 static void 355 rateest_print(const void *ip, const struct xt_entry_match *match, int numeric) 356 { 357 const struct xt_rateest_match_info *info = (const void *)match->data; 358 359 printf(" rateest match "); 360 361 printf("%s", info->name1); 362 if (info->flags & XT_RATEEST_MATCH_DELTA) 363 printf(" delta"); 364 365 if (info->flags & XT_RATEEST_MATCH_BPS) { 366 printf(" bps"); 367 if (info->flags & XT_RATEEST_MATCH_DELTA) 368 rateest_print_rate(info->bps1, numeric); 369 if (info->flags & XT_RATEEST_MATCH_ABS) { 370 rateest_print_mode(info, ""); 371 rateest_print_rate(info->bps2, numeric); 372 } 373 } 374 if (info->flags & XT_RATEEST_MATCH_PPS) { 375 printf(" pps"); 376 if (info->flags & XT_RATEEST_MATCH_DELTA) 377 printf(" %u", info->pps1); 378 if (info->flags & XT_RATEEST_MATCH_ABS) { 379 rateest_print_mode(info, ""); 380 printf(" %u", info->pps2); 381 } 382 } 383 384 if (info->flags & XT_RATEEST_MATCH_REL) { 385 rateest_print_mode(info, ""); 386 387 printf(" %s", info->name2); 388 if (info->flags & XT_RATEEST_MATCH_DELTA) 389 printf(" delta"); 390 391 if (info->flags & XT_RATEEST_MATCH_BPS) { 392 printf(" bps"); 393 if (info->flags & XT_RATEEST_MATCH_DELTA) 394 rateest_print_rate(info->bps2, numeric); 395 } 396 if (info->flags & XT_RATEEST_MATCH_PPS) { 397 printf(" pps"); 398 if (info->flags & XT_RATEEST_MATCH_DELTA) 399 printf(" %u", info->pps2); 400 } 401 } 402 } 403 404 static void 405 rateest_save(const void *ip, const struct xt_entry_match *match) 406 { 407 const struct xt_rateest_match_info *info = (const void *)match->data; 408 409 if (info->flags & XT_RATEEST_MATCH_REL) { 410 printf(" --rateest1 %s", info->name1); 411 if (info->flags & XT_RATEEST_MATCH_BPS) 412 printf(" --rateest-bps"); 413 if (info->flags & XT_RATEEST_MATCH_PPS) 414 printf(" --rateest-pps"); 415 rateest_print_mode(info, " --rateest-"); 416 printf(" --rateest2 %s", info->name2); 417 } else { 418 printf(" --rateest %s", info->name1); 419 if (info->flags & XT_RATEEST_MATCH_BPS) { 420 printf(" --rateest-bps1"); 421 rateest_print_rate(info->bps1, 0); 422 printf(" --rateest-bps2"); 423 rateest_print_rate(info->bps2, 0); 424 rateest_print_mode(info, "--rateest-"); 425 } 426 if (info->flags & XT_RATEEST_MATCH_PPS) { 427 printf(" --rateest-pps"); 428 rateest_print_mode(info, "--rateest-"); 429 printf(" %u", info->pps2); 430 } 431 } 432 } 433 434 static struct xtables_match rateest_mt_reg = { 435 .family = NFPROTO_UNSPEC, 436 .name = "rateest", 437 .version = XTABLES_VERSION, 438 .size = XT_ALIGN(sizeof(struct xt_rateest_match_info)), 439 .userspacesize = XT_ALIGN(offsetof(struct xt_rateest_match_info, est1)), 440 .help = rateest_help, 441 .parse = rateest_parse, 442 .final_check = rateest_final_check, 443 .print = rateest_print, 444 .save = rateest_save, 445 .extra_opts = rateest_opts, 446 }; 447 448 void _init(void) 449 { 450 xtables_register_match(&rateest_mt_reg); 451 } 452