libxt_statistic.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #include <math.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <xtables.h>
  5. #include <linux/netfilter/xt_statistic.h>
  6. enum {
  7. O_MODE = 0,
  8. O_PROBABILITY,
  9. O_EVERY,
  10. O_PACKET,
  11. F_PROBABILITY = 1 << O_PROBABILITY,
  12. F_EVERY = 1 << O_EVERY,
  13. F_PACKET = 1 << O_PACKET,
  14. };
  15. static void statistic_help(void)
  16. {
  17. printf(
  18. "statistic match options:\n"
  19. " --mode mode Match mode (random, nth)\n"
  20. " random mode:\n"
  21. "[!] --probability p Probability\n"
  22. " nth mode:\n"
  23. "[!] --every n Match every nth packet\n"
  24. " --packet p Initial counter value (0 <= p <= n-1, default 0)\n");
  25. }
  26. #define s struct xt_statistic_info
  27. static const struct xt_option_entry statistic_opts[] = {
  28. {.name = "mode", .id = O_MODE, .type = XTTYPE_STRING,
  29. .flags = XTOPT_MAND},
  30. {.name = "probability", .id = O_PROBABILITY, .type = XTTYPE_DOUBLE,
  31. .flags = XTOPT_INVERT, .min = 0, .max = 1,
  32. .excl = F_EVERY | F_PACKET},
  33. {.name = "every", .id = O_EVERY, .type = XTTYPE_UINT32, .min = 1,
  34. .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, u.nth.every),
  35. .excl = F_PROBABILITY, .also = F_PACKET},
  36. {.name = "packet", .id = O_PACKET, .type = XTTYPE_UINT32,
  37. .flags = XTOPT_PUT, XTOPT_POINTER(s, u.nth.packet),
  38. .excl = F_PROBABILITY, .also = F_EVERY},
  39. XTOPT_TABLEEND,
  40. };
  41. #undef s
  42. static void statistic_parse(struct xt_option_call *cb)
  43. {
  44. struct xt_statistic_info *info = cb->data;
  45. if (cb->invert)
  46. info->flags |= XT_STATISTIC_INVERT;
  47. xtables_option_parse(cb);
  48. switch (cb->entry->id) {
  49. case O_MODE:
  50. if (strcmp(cb->arg, "random") == 0)
  51. info->mode = XT_STATISTIC_MODE_RANDOM;
  52. else if (strcmp(cb->arg, "nth") == 0)
  53. info->mode = XT_STATISTIC_MODE_NTH;
  54. else
  55. xtables_error(PARAMETER_PROBLEM, "Bad mode \"%s\"",
  56. cb->arg);
  57. break;
  58. case O_PROBABILITY:
  59. info->u.random.probability = lround(0x80000000 * cb->val.dbl);
  60. break;
  61. case O_EVERY:
  62. --info->u.nth.every;
  63. break;
  64. }
  65. }
  66. static void statistic_check(struct xt_fcheck_call *cb)
  67. {
  68. struct xt_statistic_info *info = cb->data;
  69. if (info->mode == XT_STATISTIC_MODE_RANDOM &&
  70. !(cb->xflags & F_PROBABILITY))
  71. xtables_error(PARAMETER_PROBLEM,
  72. "--probability must be specified when using "
  73. "random mode");
  74. if (info->mode == XT_STATISTIC_MODE_NTH &&
  75. !(cb->xflags & (F_EVERY | F_PACKET)))
  76. xtables_error(PARAMETER_PROBLEM,
  77. "--every and --packet must be specified when "
  78. "using nth mode");
  79. /* at this point, info->u.nth.every have been decreased. */
  80. if (info->u.nth.packet > info->u.nth.every)
  81. xtables_error(PARAMETER_PROBLEM,
  82. "the --packet p must be 0 <= p <= n-1");
  83. info->u.nth.count = info->u.nth.every - info->u.nth.packet;
  84. }
  85. static void print_match(const struct xt_statistic_info *info, char *prefix)
  86. {
  87. switch (info->mode) {
  88. case XT_STATISTIC_MODE_RANDOM:
  89. printf(" %smode random%s %sprobability %.11f", prefix,
  90. (info->flags & XT_STATISTIC_INVERT) ? " !" : "",
  91. prefix,
  92. 1.0 * info->u.random.probability / 0x80000000);
  93. break;
  94. case XT_STATISTIC_MODE_NTH:
  95. printf(" %smode nth%s %severy %u", prefix,
  96. (info->flags & XT_STATISTIC_INVERT) ? " !" : "",
  97. prefix,
  98. info->u.nth.every + 1);
  99. if (info->u.nth.packet || *prefix)
  100. printf(" %spacket %u", prefix, info->u.nth.packet);
  101. break;
  102. }
  103. }
  104. static void
  105. statistic_print(const void *ip, const struct xt_entry_match *match, int numeric)
  106. {
  107. const struct xt_statistic_info *info = (const void *)match->data;
  108. printf(" statistic");
  109. print_match(info, "");
  110. }
  111. static void statistic_save(const void *ip, const struct xt_entry_match *match)
  112. {
  113. const struct xt_statistic_info *info = (const void *)match->data;
  114. print_match(info, "--");
  115. }
  116. static struct xtables_match statistic_match = {
  117. .family = NFPROTO_UNSPEC,
  118. .name = "statistic",
  119. .version = XTABLES_VERSION,
  120. .size = XT_ALIGN(sizeof(struct xt_statistic_info)),
  121. .userspacesize = offsetof(struct xt_statistic_info, u.nth.count),
  122. .help = statistic_help,
  123. .x6_parse = statistic_parse,
  124. .x6_fcheck = statistic_check,
  125. .print = statistic_print,
  126. .save = statistic_save,
  127. .x6_options = statistic_opts,
  128. };
  129. void _init(void)
  130. {
  131. xtables_register_match(&statistic_match);
  132. }