libip6t_icmp6.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. #include <stdint.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <xtables.h>
  5. #include <limits.h> /* INT_MAX in ip6_tables.h */
  6. #include <linux/netfilter_ipv6/ip6_tables.h>
  7. enum {
  8. O_ICMPV6_TYPE = 0,
  9. };
  10. struct icmpv6_names {
  11. const char *name;
  12. uint8_t type;
  13. uint8_t code_min, code_max;
  14. };
  15. static const struct icmpv6_names icmpv6_codes[] = {
  16. { "destination-unreachable", 1, 0, 0xFF },
  17. { "no-route", 1, 0, 0 },
  18. { "communication-prohibited", 1, 1, 1 },
  19. { "address-unreachable", 1, 3, 3 },
  20. { "port-unreachable", 1, 4, 4 },
  21. { "packet-too-big", 2, 0, 0xFF },
  22. { "time-exceeded", 3, 0, 0xFF },
  23. /* Alias */ { "ttl-exceeded", 3, 0, 0xFF },
  24. { "ttl-zero-during-transit", 3, 0, 0 },
  25. { "ttl-zero-during-reassembly", 3, 1, 1 },
  26. { "parameter-problem", 4, 0, 0xFF },
  27. { "bad-header", 4, 0, 0 },
  28. { "unknown-header-type", 4, 1, 1 },
  29. { "unknown-option", 4, 2, 2 },
  30. { "echo-request", 128, 0, 0xFF },
  31. /* Alias */ { "ping", 128, 0, 0xFF },
  32. { "echo-reply", 129, 0, 0xFF },
  33. /* Alias */ { "pong", 129, 0, 0xFF },
  34. { "router-solicitation", 133, 0, 0xFF },
  35. { "router-advertisement", 134, 0, 0xFF },
  36. { "neighbour-solicitation", 135, 0, 0xFF },
  37. /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF },
  38. { "neighbour-advertisement", 136, 0, 0xFF },
  39. /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF },
  40. { "redirect", 137, 0, 0xFF },
  41. };
  42. static void
  43. print_icmpv6types(void)
  44. {
  45. unsigned int i;
  46. printf("Valid ICMPv6 Types:");
  47. for (i = 0; i < ARRAY_SIZE(icmpv6_codes); ++i) {
  48. if (i && icmpv6_codes[i].type == icmpv6_codes[i-1].type) {
  49. if (icmpv6_codes[i].code_min == icmpv6_codes[i-1].code_min
  50. && (icmpv6_codes[i].code_max
  51. == icmpv6_codes[i-1].code_max))
  52. printf(" (%s)", icmpv6_codes[i].name);
  53. else
  54. printf("\n %s", icmpv6_codes[i].name);
  55. }
  56. else
  57. printf("\n%s", icmpv6_codes[i].name);
  58. }
  59. printf("\n");
  60. }
  61. static void icmp6_help(void)
  62. {
  63. printf(
  64. "icmpv6 match options:\n"
  65. "[!] --icmpv6-type typename match icmpv6 type\n"
  66. " (or numeric type or type/code)\n");
  67. print_icmpv6types();
  68. }
  69. static const struct xt_option_entry icmp6_opts[] = {
  70. {.name = "icmpv6-type", .id = O_ICMPV6_TYPE, .type = XTTYPE_STRING,
  71. .flags = XTOPT_MAND | XTOPT_INVERT},
  72. XTOPT_TABLEEND,
  73. };
  74. static void
  75. parse_icmpv6(const char *icmpv6type, uint8_t *type, uint8_t code[])
  76. {
  77. static const unsigned int limit = ARRAY_SIZE(icmpv6_codes);
  78. unsigned int match = limit;
  79. unsigned int i;
  80. for (i = 0; i < limit; i++) {
  81. if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type))
  82. == 0) {
  83. if (match != limit)
  84. xtables_error(PARAMETER_PROBLEM,
  85. "Ambiguous ICMPv6 type `%s':"
  86. " `%s' or `%s'?",
  87. icmpv6type,
  88. icmpv6_codes[match].name,
  89. icmpv6_codes[i].name);
  90. match = i;
  91. }
  92. }
  93. if (match != limit) {
  94. *type = icmpv6_codes[match].type;
  95. code[0] = icmpv6_codes[match].code_min;
  96. code[1] = icmpv6_codes[match].code_max;
  97. } else {
  98. char *slash;
  99. char buffer[strlen(icmpv6type) + 1];
  100. unsigned int number;
  101. strcpy(buffer, icmpv6type);
  102. slash = strchr(buffer, '/');
  103. if (slash)
  104. *slash = '\0';
  105. if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX))
  106. xtables_error(PARAMETER_PROBLEM,
  107. "Invalid ICMPv6 type `%s'\n", buffer);
  108. *type = number;
  109. if (slash) {
  110. if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX))
  111. xtables_error(PARAMETER_PROBLEM,
  112. "Invalid ICMPv6 code `%s'\n",
  113. slash+1);
  114. code[0] = code[1] = number;
  115. } else {
  116. code[0] = 0;
  117. code[1] = 0xFF;
  118. }
  119. }
  120. }
  121. static void icmp6_init(struct xt_entry_match *m)
  122. {
  123. struct ip6t_icmp *icmpv6info = (struct ip6t_icmp *)m->data;
  124. icmpv6info->code[1] = 0xFF;
  125. }
  126. static void icmp6_parse(struct xt_option_call *cb)
  127. {
  128. struct ip6t_icmp *icmpv6info = cb->data;
  129. xtables_option_parse(cb);
  130. parse_icmpv6(cb->arg, &icmpv6info->type, icmpv6info->code);
  131. if (cb->invert)
  132. icmpv6info->invflags |= IP6T_ICMP_INV;
  133. }
  134. static void print_icmpv6type(uint8_t type,
  135. uint8_t code_min, uint8_t code_max,
  136. int invert,
  137. int numeric)
  138. {
  139. if (!numeric) {
  140. unsigned int i;
  141. for (i = 0; i < ARRAY_SIZE(icmpv6_codes); ++i)
  142. if (icmpv6_codes[i].type == type
  143. && icmpv6_codes[i].code_min == code_min
  144. && icmpv6_codes[i].code_max == code_max)
  145. break;
  146. if (i != ARRAY_SIZE(icmpv6_codes)) {
  147. printf(" %s%s",
  148. invert ? "!" : "",
  149. icmpv6_codes[i].name);
  150. return;
  151. }
  152. }
  153. if (invert)
  154. printf(" !");
  155. printf("type %u", type);
  156. if (code_min == code_max)
  157. printf(" code %u", code_min);
  158. else if (code_min != 0 || code_max != 0xFF)
  159. printf(" codes %u-%u", code_min, code_max);
  160. }
  161. static void icmp6_print(const void *ip, const struct xt_entry_match *match,
  162. int numeric)
  163. {
  164. const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data;
  165. printf(" ipv6-icmp");
  166. print_icmpv6type(icmpv6->type, icmpv6->code[0], icmpv6->code[1],
  167. icmpv6->invflags & IP6T_ICMP_INV,
  168. numeric);
  169. if (icmpv6->invflags & ~IP6T_ICMP_INV)
  170. printf(" Unknown invflags: 0x%X",
  171. icmpv6->invflags & ~IP6T_ICMP_INV);
  172. }
  173. static void icmp6_save(const void *ip, const struct xt_entry_match *match)
  174. {
  175. const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data;
  176. if (icmpv6->invflags & IP6T_ICMP_INV)
  177. printf(" !");
  178. printf(" --icmpv6-type %u", icmpv6->type);
  179. if (icmpv6->code[0] != 0 || icmpv6->code[1] != 0xFF)
  180. printf("/%u", icmpv6->code[0]);
  181. }
  182. static struct xtables_match icmp6_mt6_reg = {
  183. .name = "icmp6",
  184. .version = XTABLES_VERSION,
  185. .family = NFPROTO_IPV6,
  186. .size = XT_ALIGN(sizeof(struct ip6t_icmp)),
  187. .userspacesize = XT_ALIGN(sizeof(struct ip6t_icmp)),
  188. .help = icmp6_help,
  189. .init = icmp6_init,
  190. .print = icmp6_print,
  191. .save = icmp6_save,
  192. .x6_parse = icmp6_parse,
  193. .x6_options = icmp6_opts,
  194. };
  195. void _init(void)
  196. {
  197. xtables_register_match(&icmp6_mt6_reg);
  198. }