libxt_connlimit.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. #include <stdio.h>
  2. #include <netdb.h>
  3. #include <string.h>
  4. #include <xtables.h>
  5. #include <linux/netfilter/xt_connlimit.h>
  6. enum {
  7. O_UPTO = 0,
  8. O_ABOVE,
  9. O_MASK,
  10. O_SADDR,
  11. O_DADDR,
  12. F_UPTO = 1 << O_UPTO,
  13. F_ABOVE = 1 << O_ABOVE,
  14. F_MASK = 1 << O_MASK,
  15. F_SADDR = 1 << O_SADDR,
  16. F_DADDR = 1 << O_DADDR,
  17. };
  18. static void connlimit_help(void)
  19. {
  20. printf(
  21. "connlimit match options:\n"
  22. " --connlimit-upto n match if the number of existing connections is 0..n\n"
  23. " --connlimit-above n match if the number of existing connections is >n\n"
  24. " --connlimit-mask n group hosts using prefix length (default: max len)\n"
  25. " --connlimit-saddr select source address for grouping\n"
  26. " --connlimit-daddr select destination addresses for grouping\n");
  27. }
  28. #define s struct xt_connlimit_info
  29. static const struct xt_option_entry connlimit_opts[] = {
  30. {.name = "connlimit-upto", .id = O_UPTO, .excl = F_ABOVE,
  31. .type = XTTYPE_UINT32, .flags = XTOPT_INVERT | XTOPT_PUT,
  32. XTOPT_POINTER(s, limit)},
  33. {.name = "connlimit-above", .id = O_ABOVE, .excl = F_UPTO,
  34. .type = XTTYPE_UINT32, .flags = XTOPT_INVERT | XTOPT_PUT,
  35. XTOPT_POINTER(s, limit)},
  36. {.name = "connlimit-mask", .id = O_MASK, .type = XTTYPE_PLENMASK,
  37. .flags = XTOPT_PUT, XTOPT_POINTER(s, mask)},
  38. {.name = "connlimit-saddr", .id = O_SADDR, .excl = F_DADDR,
  39. .type = XTTYPE_NONE},
  40. {.name = "connlimit-daddr", .id = O_DADDR, .excl = F_SADDR,
  41. .type = XTTYPE_NONE},
  42. XTOPT_TABLEEND,
  43. };
  44. #undef s
  45. static void connlimit_init(struct xt_entry_match *match)
  46. {
  47. struct xt_connlimit_info *info = (void *)match->data;
  48. /* This will also initialize the v4 mask correctly */
  49. memset(info->v6_mask, 0xFF, sizeof(info->v6_mask));
  50. }
  51. static void connlimit_parse(struct xt_option_call *cb, uint8_t family)
  52. {
  53. struct xt_connlimit_info *info = cb->data;
  54. const unsigned int revision = (*cb->match)->u.user.revision;
  55. xtables_option_parse(cb);
  56. switch (cb->entry->id) {
  57. case O_ABOVE:
  58. if (cb->invert)
  59. info->flags |= XT_CONNLIMIT_INVERT;
  60. break;
  61. case O_UPTO:
  62. if (!cb->invert)
  63. info->flags |= XT_CONNLIMIT_INVERT;
  64. break;
  65. case O_SADDR:
  66. if (revision < 1)
  67. xtables_error(PARAMETER_PROBLEM,
  68. "xt_connlimit.0 does not support "
  69. "--connlimit-daddr");
  70. info->flags &= ~XT_CONNLIMIT_DADDR;
  71. break;
  72. case O_DADDR:
  73. if (revision < 1)
  74. xtables_error(PARAMETER_PROBLEM,
  75. "xt_connlimit.0 does not support "
  76. "--connlimit-daddr");
  77. info->flags |= XT_CONNLIMIT_DADDR;
  78. break;
  79. }
  80. }
  81. static void connlimit_parse4(struct xt_option_call *cb)
  82. {
  83. return connlimit_parse(cb, NFPROTO_IPV4);
  84. }
  85. static void connlimit_parse6(struct xt_option_call *cb)
  86. {
  87. return connlimit_parse(cb, NFPROTO_IPV6);
  88. }
  89. static void connlimit_check(struct xt_fcheck_call *cb)
  90. {
  91. if ((cb->xflags & (F_UPTO | F_ABOVE)) == 0)
  92. xtables_error(PARAMETER_PROBLEM,
  93. "You must specify \"--connlimit-above\" or "
  94. "\"--connlimit-upto\".");
  95. }
  96. static unsigned int count_bits4(uint32_t mask)
  97. {
  98. unsigned int bits = 0;
  99. for (mask = ~ntohl(mask); mask != 0; mask >>= 1)
  100. ++bits;
  101. return 32 - bits;
  102. }
  103. static unsigned int count_bits6(const uint32_t *mask)
  104. {
  105. unsigned int bits = 0, i;
  106. uint32_t tmp[4];
  107. for (i = 0; i < 4; ++i)
  108. for (tmp[i] = ~ntohl(mask[i]); tmp[i] != 0; tmp[i] >>= 1)
  109. ++bits;
  110. return 128 - bits;
  111. }
  112. static void connlimit_print4(const void *ip,
  113. const struct xt_entry_match *match, int numeric)
  114. {
  115. const struct xt_connlimit_info *info = (const void *)match->data;
  116. printf(" #conn %s/%u %s %u",
  117. (info->flags & XT_CONNLIMIT_DADDR) ? "dst" : "src",
  118. count_bits4(info->v4_mask),
  119. (info->flags & XT_CONNLIMIT_INVERT) ? "<=" : ">", info->limit);
  120. }
  121. static void connlimit_print6(const void *ip,
  122. const struct xt_entry_match *match, int numeric)
  123. {
  124. const struct xt_connlimit_info *info = (const void *)match->data;
  125. printf(" #conn %s/%u %s %u",
  126. (info->flags & XT_CONNLIMIT_DADDR) ? "dst" : "src",
  127. count_bits6(info->v6_mask),
  128. (info->flags & XT_CONNLIMIT_INVERT) ? "<=" : ">", info->limit);
  129. }
  130. static void connlimit_save4(const void *ip, const struct xt_entry_match *match)
  131. {
  132. const struct xt_connlimit_info *info = (const void *)match->data;
  133. const int revision = match->u.user.revision;
  134. if (info->flags & XT_CONNLIMIT_INVERT)
  135. printf(" --connlimit-upto %u", info->limit);
  136. else
  137. printf(" --connlimit-above %u", info->limit);
  138. printf(" --connlimit-mask %u", count_bits4(info->v4_mask));
  139. if (revision >= 1) {
  140. if (info->flags & XT_CONNLIMIT_DADDR)
  141. printf(" --connlimit-daddr");
  142. else
  143. printf(" --connlimit-saddr");
  144. }
  145. }
  146. static void connlimit_save6(const void *ip, const struct xt_entry_match *match)
  147. {
  148. const struct xt_connlimit_info *info = (const void *)match->data;
  149. const int revision = match->u.user.revision;
  150. if (info->flags & XT_CONNLIMIT_INVERT)
  151. printf(" --connlimit-upto %u", info->limit);
  152. else
  153. printf(" --connlimit-above %u", info->limit);
  154. printf(" --connlimit-mask %u", count_bits6(info->v6_mask));
  155. if (revision >= 1) {
  156. if (info->flags & XT_CONNLIMIT_DADDR)
  157. printf(" --connlimit-daddr");
  158. else
  159. printf(" --connlimit-saddr");
  160. }
  161. }
  162. static struct xtables_match connlimit_mt_reg[] = {
  163. {
  164. .name = "connlimit",
  165. .revision = 0,
  166. .family = NFPROTO_IPV4,
  167. .version = XTABLES_VERSION,
  168. .size = XT_ALIGN(sizeof(struct xt_connlimit_info)),
  169. .userspacesize = offsetof(struct xt_connlimit_info, data),
  170. .help = connlimit_help,
  171. .init = connlimit_init,
  172. .x6_parse = connlimit_parse4,
  173. .x6_fcheck = connlimit_check,
  174. .print = connlimit_print4,
  175. .save = connlimit_save4,
  176. .x6_options = connlimit_opts,
  177. },
  178. {
  179. .name = "connlimit",
  180. .revision = 0,
  181. .family = NFPROTO_IPV6,
  182. .version = XTABLES_VERSION,
  183. .size = XT_ALIGN(sizeof(struct xt_connlimit_info)),
  184. .userspacesize = offsetof(struct xt_connlimit_info, data),
  185. .help = connlimit_help,
  186. .init = connlimit_init,
  187. .x6_parse = connlimit_parse6,
  188. .x6_fcheck = connlimit_check,
  189. .print = connlimit_print6,
  190. .save = connlimit_save6,
  191. .x6_options = connlimit_opts,
  192. },
  193. {
  194. .name = "connlimit",
  195. .revision = 1,
  196. .family = NFPROTO_IPV4,
  197. .version = XTABLES_VERSION,
  198. .size = XT_ALIGN(sizeof(struct xt_connlimit_info)),
  199. .userspacesize = offsetof(struct xt_connlimit_info, data),
  200. .help = connlimit_help,
  201. .init = connlimit_init,
  202. .x6_parse = connlimit_parse4,
  203. .x6_fcheck = connlimit_check,
  204. .print = connlimit_print4,
  205. .save = connlimit_save4,
  206. .x6_options = connlimit_opts,
  207. },
  208. {
  209. .name = "connlimit",
  210. .revision = 1,
  211. .family = NFPROTO_IPV6,
  212. .version = XTABLES_VERSION,
  213. .size = XT_ALIGN(sizeof(struct xt_connlimit_info)),
  214. .userspacesize = offsetof(struct xt_connlimit_info, data),
  215. .help = connlimit_help,
  216. .init = connlimit_init,
  217. .x6_parse = connlimit_parse6,
  218. .x6_fcheck = connlimit_check,
  219. .print = connlimit_print6,
  220. .save = connlimit_save6,
  221. .x6_options = connlimit_opts,
  222. },
  223. };
  224. void _init(void)
  225. {
  226. xtables_register_matches(connlimit_mt_reg, ARRAY_SIZE(connlimit_mt_reg));
  227. }