libip6t_rt.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <xtables.h>
  5. #include <linux/netfilter_ipv6/ip6t_rt.h>
  6. #include <arpa/inet.h>
  7. enum {
  8. O_RT_TYPE = 0,
  9. O_RT_SEGSLEFT,
  10. O_RT_LEN,
  11. O_RT0RES,
  12. O_RT0ADDRS,
  13. O_RT0NSTRICT,
  14. F_RT_TYPE = 1 << O_RT_TYPE,
  15. F_RT0ADDRS = 1 << O_RT0ADDRS,
  16. };
  17. static void rt_help(void)
  18. {
  19. printf(
  20. "rt match options:\n"
  21. "[!] --rt-type type match the type\n"
  22. "[!] --rt-segsleft num[:num] match the Segments Left field (range)\n"
  23. "[!] --rt-len length total length of this header\n"
  24. " --rt-0-res check the reserved field too (type 0)\n"
  25. " --rt-0-addrs ADDR[,ADDR...] Type=0 addresses (list, max: %d)\n"
  26. " --rt-0-not-strict List of Type=0 addresses not a strict list\n",
  27. IP6T_RT_HOPS);
  28. }
  29. #define s struct ip6t_rt
  30. static const struct xt_option_entry rt_opts[] = {
  31. {.name = "rt-type", .id = O_RT_TYPE, .type = XTTYPE_UINT32,
  32. .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, rt_type)},
  33. {.name = "rt-segsleft", .id = O_RT_SEGSLEFT, .type = XTTYPE_UINT32RC,
  34. .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segsleft)},
  35. {.name = "rt-len", .id = O_RT_LEN, .type = XTTYPE_UINT32,
  36. .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdrlen)},
  37. {.name = "rt-0-res", .id = O_RT0RES, .type = XTTYPE_NONE},
  38. {.name = "rt-0-addrs", .id = O_RT0ADDRS, .type = XTTYPE_STRING},
  39. {.name = "rt-0-not-strict", .id = O_RT0NSTRICT, .type = XTTYPE_NONE},
  40. XTOPT_TABLEEND,
  41. };
  42. #undef s
  43. static const char *
  44. addr_to_numeric(const struct in6_addr *addrp)
  45. {
  46. static char buf[50+1];
  47. return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
  48. }
  49. static struct in6_addr *
  50. numeric_to_addr(const char *num)
  51. {
  52. static struct in6_addr ap;
  53. int err;
  54. if ((err=inet_pton(AF_INET6, num, &ap)) == 1)
  55. return &ap;
  56. #ifdef DEBUG
  57. fprintf(stderr, "\nnumeric2addr: %d\n", err);
  58. #endif
  59. xtables_error(PARAMETER_PROBLEM, "bad address: %s", num);
  60. return (struct in6_addr *)NULL;
  61. }
  62. static int
  63. parse_addresses(const char *addrstr, struct in6_addr *addrp)
  64. {
  65. char *buffer, *cp, *next;
  66. unsigned int i;
  67. buffer = strdup(addrstr);
  68. if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
  69. for (cp=buffer, i=0; cp && i<IP6T_RT_HOPS; cp=next,i++)
  70. {
  71. next=strchr(cp, ',');
  72. if (next) *next++='\0';
  73. memcpy(&(addrp[i]), numeric_to_addr(cp), sizeof(struct in6_addr));
  74. #if DEBUG
  75. printf("addr str: %s\n", cp);
  76. printf("addr ip6: %s\n", addr_to_numeric((numeric_to_addr(cp))));
  77. printf("addr [%d]: %s\n", i, addr_to_numeric(&(addrp[i])));
  78. #endif
  79. }
  80. if (cp) xtables_error(PARAMETER_PROBLEM, "too many addresses specified");
  81. free(buffer);
  82. #if DEBUG
  83. printf("addr nr: %d\n", i);
  84. #endif
  85. return i;
  86. }
  87. static void rt_parse(struct xt_option_call *cb)
  88. {
  89. struct ip6t_rt *rtinfo = cb->data;
  90. xtables_option_parse(cb);
  91. switch (cb->entry->id) {
  92. case O_RT_TYPE:
  93. if (cb->invert)
  94. rtinfo->invflags |= IP6T_RT_INV_TYP;
  95. rtinfo->flags |= IP6T_RT_TYP;
  96. break;
  97. case O_RT_SEGSLEFT:
  98. if (cb->nvals == 1)
  99. rtinfo->segsleft[1] = rtinfo->segsleft[0];
  100. if (cb->invert)
  101. rtinfo->invflags |= IP6T_RT_INV_SGS;
  102. rtinfo->flags |= IP6T_RT_SGS;
  103. break;
  104. case O_RT_LEN:
  105. if (cb->invert)
  106. rtinfo->invflags |= IP6T_RT_INV_LEN;
  107. rtinfo->flags |= IP6T_RT_LEN;
  108. break;
  109. case O_RT0RES:
  110. if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 ||
  111. rtinfo->invflags & IP6T_RT_INV_TYP)
  112. xtables_error(PARAMETER_PROBLEM,
  113. "`--rt-type 0' required before `--rt-0-res'");
  114. rtinfo->flags |= IP6T_RT_RES;
  115. break;
  116. case O_RT0ADDRS:
  117. if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 ||
  118. rtinfo->invflags & IP6T_RT_INV_TYP)
  119. xtables_error(PARAMETER_PROBLEM,
  120. "`--rt-type 0' required before `--rt-0-addrs'");
  121. rtinfo->addrnr = parse_addresses(cb->arg, rtinfo->addrs);
  122. rtinfo->flags |= IP6T_RT_FST;
  123. break;
  124. case O_RT0NSTRICT:
  125. if (!(cb->xflags & F_RT0ADDRS))
  126. xtables_error(PARAMETER_PROBLEM,
  127. "`--rt-0-addr ...' required before `--rt-0-not-strict'");
  128. rtinfo->flags |= IP6T_RT_FST_NSTRICT;
  129. break;
  130. }
  131. }
  132. static void
  133. print_nums(const char *name, uint32_t min, uint32_t max,
  134. int invert)
  135. {
  136. const char *inv = invert ? "!" : "";
  137. if (min != 0 || max != 0xFFFFFFFF || invert) {
  138. printf(" %s", name);
  139. if (min == max) {
  140. printf(":%s", inv);
  141. printf("%u", min);
  142. } else {
  143. printf("s:%s", inv);
  144. printf("%u",min);
  145. printf(":");
  146. printf("%u",max);
  147. }
  148. }
  149. }
  150. static void
  151. print_addresses(unsigned int addrnr, struct in6_addr *addrp)
  152. {
  153. unsigned int i;
  154. for(i=0; i<addrnr; i++){
  155. printf("%c%s", (i==0)?' ':',', addr_to_numeric(&(addrp[i])));
  156. }
  157. }
  158. static void rt_print(const void *ip, const struct xt_entry_match *match,
  159. int numeric)
  160. {
  161. const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
  162. printf(" rt");
  163. if (rtinfo->flags & IP6T_RT_TYP)
  164. printf(" type:%s%d", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "",
  165. rtinfo->rt_type);
  166. print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1],
  167. rtinfo->invflags & IP6T_RT_INV_SGS);
  168. if (rtinfo->flags & IP6T_RT_LEN) {
  169. printf(" length");
  170. printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : "");
  171. printf("%u", rtinfo->hdrlen);
  172. }
  173. if (rtinfo->flags & IP6T_RT_RES) printf(" reserved");
  174. if (rtinfo->flags & IP6T_RT_FST) printf(" 0-addrs");
  175. print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
  176. if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" 0-not-strict");
  177. if (rtinfo->invflags & ~IP6T_RT_INV_MASK)
  178. printf(" Unknown invflags: 0x%X",
  179. rtinfo->invflags & ~IP6T_RT_INV_MASK);
  180. }
  181. static void rt_save(const void *ip, const struct xt_entry_match *match)
  182. {
  183. const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
  184. if (rtinfo->flags & IP6T_RT_TYP) {
  185. printf("%s --rt-type %u",
  186. (rtinfo->invflags & IP6T_RT_INV_TYP) ? " !" : "",
  187. rtinfo->rt_type);
  188. }
  189. if (!(rtinfo->segsleft[0] == 0
  190. && rtinfo->segsleft[1] == 0xFFFFFFFF)) {
  191. printf("%s --rt-segsleft ",
  192. (rtinfo->invflags & IP6T_RT_INV_SGS) ? " !" : "");
  193. if (rtinfo->segsleft[0]
  194. != rtinfo->segsleft[1])
  195. printf("%u:%u",
  196. rtinfo->segsleft[0],
  197. rtinfo->segsleft[1]);
  198. else
  199. printf("%u",
  200. rtinfo->segsleft[0]);
  201. }
  202. if (rtinfo->flags & IP6T_RT_LEN) {
  203. printf("%s --rt-len %u",
  204. (rtinfo->invflags & IP6T_RT_INV_LEN) ? " !" : "",
  205. rtinfo->hdrlen);
  206. }
  207. if (rtinfo->flags & IP6T_RT_RES) printf(" --rt-0-res");
  208. if (rtinfo->flags & IP6T_RT_FST) printf(" --rt-0-addrs");
  209. print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
  210. if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" --rt-0-not-strict");
  211. }
  212. static struct xtables_match rt_mt6_reg = {
  213. .name = "rt",
  214. .version = XTABLES_VERSION,
  215. .family = NFPROTO_IPV6,
  216. .size = XT_ALIGN(sizeof(struct ip6t_rt)),
  217. .userspacesize = XT_ALIGN(sizeof(struct ip6t_rt)),
  218. .help = rt_help,
  219. .x6_parse = rt_parse,
  220. .print = rt_print,
  221. .save = rt_save,
  222. .x6_options = rt_opts,
  223. };
  224. void
  225. _init(void)
  226. {
  227. xtables_register_match(&rt_mt6_reg);
  228. }