libxt_u32.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /* Shared library add-on to iptables to add u32 matching,
  2. * generalized matching on values found at packet offsets
  3. *
  4. * Detailed doc is in the kernel module source
  5. * net/netfilter/xt_u32.c
  6. *
  7. * (C) 2002 by Don Cohen <don-netf@isis.cs3-inc.com>
  8. * Released under the terms of GNU GPL v2
  9. *
  10. * Copyright © CC Computer Consultants GmbH, 2007
  11. * Contact: <jengelh@computergmbh.de>
  12. */
  13. #include <ctype.h>
  14. #include <errno.h>
  15. #include <stdint.h>
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. #include <xtables.h>
  19. #include <linux/netfilter/xt_u32.h>
  20. enum {
  21. O_U32 = 0,
  22. };
  23. static const struct xt_option_entry u32_opts[] = {
  24. {.name = "u32", .id = O_U32, .type = XTTYPE_STRING,
  25. .flags = XTOPT_MAND | XTOPT_INVERT},
  26. XTOPT_TABLEEND,
  27. };
  28. static void u32_help(void)
  29. {
  30. printf(
  31. "u32 match options:\n"
  32. "[!] --u32 tests\n"
  33. "\t\t""tests := location \"=\" value | tests \"&&\" location \"=\" value\n"
  34. "\t\t""value := range | value \",\" range\n"
  35. "\t\t""range := number | number \":\" number\n"
  36. "\t\t""location := number | location operator number\n"
  37. "\t\t""operator := \"&\" | \"<<\" | \">>\" | \"@\"\n");
  38. }
  39. static void u32_dump(const struct xt_u32 *data)
  40. {
  41. const struct xt_u32_test *ct;
  42. unsigned int testind, i;
  43. printf(" \"");
  44. for (testind = 0; testind < data->ntests; ++testind) {
  45. ct = &data->tests[testind];
  46. if (testind > 0)
  47. printf("&&");
  48. printf("0x%x", ct->location[0].number);
  49. for (i = 1; i < ct->nnums; ++i) {
  50. switch (ct->location[i].nextop) {
  51. case XT_U32_AND:
  52. printf("&");
  53. break;
  54. case XT_U32_LEFTSH:
  55. printf("<<");
  56. break;
  57. case XT_U32_RIGHTSH:
  58. printf(">>");
  59. break;
  60. case XT_U32_AT:
  61. printf("@");
  62. break;
  63. }
  64. printf("0x%x", ct->location[i].number);
  65. }
  66. printf("=");
  67. for (i = 0; i < ct->nvalues; ++i) {
  68. if (i > 0)
  69. printf(",");
  70. if (ct->value[i].min == ct->value[i].max)
  71. printf("0x%x", ct->value[i].min);
  72. else
  73. printf("0x%x:0x%x", ct->value[i].min,
  74. ct->value[i].max);
  75. }
  76. }
  77. putchar('\"');
  78. }
  79. /* string_to_number() is not quite what we need here ... */
  80. static uint32_t parse_number(const char **s, int pos)
  81. {
  82. unsigned int number;
  83. char *end;
  84. if (!xtables_strtoui(*s, &end, &number, 0, UINT32_MAX) ||
  85. end == *s)
  86. xtables_error(PARAMETER_PROBLEM,
  87. "u32: at char %d: not a number or out of range", pos);
  88. *s = end;
  89. return number;
  90. }
  91. static void u32_parse(struct xt_option_call *cb)
  92. {
  93. struct xt_u32 *data = cb->data;
  94. unsigned int testind = 0, locind = 0, valind = 0;
  95. struct xt_u32_test *ct = &data->tests[testind]; /* current test */
  96. const char *arg = cb->arg; /* the argument string */
  97. const char *start = cb->arg;
  98. int state = 0;
  99. xtables_option_parse(cb);
  100. data->invert = cb->invert;
  101. /*
  102. * states:
  103. * 0 = looking for numbers and operations,
  104. * 1 = looking for ranges
  105. */
  106. while (1) {
  107. /* read next operand/number or range */
  108. while (isspace(*arg))
  109. ++arg;
  110. if (*arg == '\0') {
  111. /* end of argument found */
  112. if (state == 0)
  113. xtables_error(PARAMETER_PROBLEM,
  114. "u32: abrupt end of input after location specifier");
  115. if (valind == 0)
  116. xtables_error(PARAMETER_PROBLEM,
  117. "u32: test ended with no value specified");
  118. ct->nnums = locind;
  119. ct->nvalues = valind;
  120. data->ntests = ++testind;
  121. if (testind > XT_U32_MAXSIZE)
  122. xtables_error(PARAMETER_PROBLEM,
  123. "u32: at char %u: too many \"&&\"s",
  124. (unsigned int)(arg - start));
  125. return;
  126. }
  127. if (state == 0) {
  128. /*
  129. * reading location: read a number if nothing read yet,
  130. * otherwise either op number or = to end location spec
  131. */
  132. if (*arg == '=') {
  133. if (locind == 0) {
  134. xtables_error(PARAMETER_PROBLEM,
  135. "u32: at char %u: "
  136. "location spec missing",
  137. (unsigned int)(arg - start));
  138. } else {
  139. ++arg;
  140. state = 1;
  141. }
  142. } else {
  143. if (locind != 0) {
  144. /* need op before number */
  145. if (*arg == '&') {
  146. ct->location[locind].nextop = XT_U32_AND;
  147. } else if (*arg == '<') {
  148. if (*++arg != '<')
  149. xtables_error(PARAMETER_PROBLEM,
  150. "u32: at char %u: a second '<' was expected", (unsigned int)(arg - start));
  151. ct->location[locind].nextop = XT_U32_LEFTSH;
  152. } else if (*arg == '>') {
  153. if (*++arg != '>')
  154. xtables_error(PARAMETER_PROBLEM,
  155. "u32: at char %u: a second '>' was expected", (unsigned int)(arg - start));
  156. ct->location[locind].nextop = XT_U32_RIGHTSH;
  157. } else if (*arg == '@') {
  158. ct->location[locind].nextop = XT_U32_AT;
  159. } else {
  160. xtables_error(PARAMETER_PROBLEM,
  161. "u32: at char %u: operator expected", (unsigned int)(arg - start));
  162. }
  163. ++arg;
  164. }
  165. /* now a number; string_to_number skips white space? */
  166. ct->location[locind].number =
  167. parse_number(&arg, arg - start);
  168. if (++locind > XT_U32_MAXSIZE)
  169. xtables_error(PARAMETER_PROBLEM,
  170. "u32: at char %u: too many operators", (unsigned int)(arg - start));
  171. }
  172. } else {
  173. /*
  174. * state 1 - reading values: read a range if nothing
  175. * read yet, otherwise either ,range or && to end
  176. * test spec
  177. */
  178. if (*arg == '&') {
  179. if (*++arg != '&')
  180. xtables_error(PARAMETER_PROBLEM,
  181. "u32: at char %u: a second '&' was expected", (unsigned int)(arg - start));
  182. if (valind == 0) {
  183. xtables_error(PARAMETER_PROBLEM,
  184. "u32: at char %u: value spec missing", (unsigned int)(arg - start));
  185. } else {
  186. ct->nnums = locind;
  187. ct->nvalues = valind;
  188. ct = &data->tests[++testind];
  189. if (testind > XT_U32_MAXSIZE)
  190. xtables_error(PARAMETER_PROBLEM,
  191. "u32: at char %u: too many \"&&\"s", (unsigned int)(arg - start));
  192. ++arg;
  193. state = 0;
  194. locind = 0;
  195. valind = 0;
  196. }
  197. } else { /* read value range */
  198. if (valind > 0) { /* need , before number */
  199. if (*arg != ',')
  200. xtables_error(PARAMETER_PROBLEM,
  201. "u32: at char %u: expected \",\" or \"&&\"", (unsigned int)(arg - start));
  202. ++arg;
  203. }
  204. ct->value[valind].min =
  205. parse_number(&arg, arg - start);
  206. while (isspace(*arg))
  207. ++arg;
  208. if (*arg == ':') {
  209. ++arg;
  210. ct->value[valind].max =
  211. parse_number(&arg, arg-start);
  212. } else {
  213. ct->value[valind].max =
  214. ct->value[valind].min;
  215. }
  216. if (++valind > XT_U32_MAXSIZE)
  217. xtables_error(PARAMETER_PROBLEM,
  218. "u32: at char %u: too many \",\"s", (unsigned int)(arg - start));
  219. }
  220. }
  221. }
  222. }
  223. static void u32_print(const void *ip, const struct xt_entry_match *match,
  224. int numeric)
  225. {
  226. const struct xt_u32 *data = (const void *)match->data;
  227. printf(" u32");
  228. if (data->invert)
  229. printf(" !");
  230. u32_dump(data);
  231. }
  232. static void u32_save(const void *ip, const struct xt_entry_match *match)
  233. {
  234. const struct xt_u32 *data = (const void *)match->data;
  235. if (data->invert)
  236. printf(" !");
  237. printf(" --u32");
  238. u32_dump(data);
  239. }
  240. static struct xtables_match u32_match = {
  241. .name = "u32",
  242. .family = NFPROTO_UNSPEC,
  243. .version = XTABLES_VERSION,
  244. .size = XT_ALIGN(sizeof(struct xt_u32)),
  245. .userspacesize = XT_ALIGN(sizeof(struct xt_u32)),
  246. .help = u32_help,
  247. .print = u32_print,
  248. .save = u32_save,
  249. .x6_parse = u32_parse,
  250. .x6_options = u32_opts,
  251. };
  252. void _init(void)
  253. {
  254. xtables_register_match(&u32_match);
  255. }