/net/ipv6/netfilter/ip6t_rt.c

https://bitbucket.org/Don2x/mod-kernel-m7-sources · C · 223 lines · 189 code · 28 blank · 6 comment · 39 complexity · 19c13a6b3206bfb34297047999d4b381 MD5 · raw file

  1. /* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu>
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 as
  5. * published by the Free Software Foundation.
  6. */
  7. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  8. #include <linux/module.h>
  9. #include <linux/skbuff.h>
  10. #include <linux/ipv6.h>
  11. #include <linux/types.h>
  12. #include <net/checksum.h>
  13. #include <net/ipv6.h>
  14. #include <asm/byteorder.h>
  15. #include <linux/netfilter/x_tables.h>
  16. #include <linux/netfilter_ipv6/ip6_tables.h>
  17. #include <linux/netfilter_ipv6/ip6t_rt.h>
  18. MODULE_LICENSE("GPL");
  19. MODULE_DESCRIPTION("Xtables: IPv6 Routing Header match");
  20. MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
  21. static inline bool
  22. segsleft_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert)
  23. {
  24. bool r;
  25. pr_debug("segsleft_match:%c 0x%x <= 0x%x <= 0x%x\n",
  26. invert ? '!' : ' ', min, id, max);
  27. r = (id >= min && id <= max) ^ invert;
  28. pr_debug(" result %s\n", r ? "PASS" : "FAILED");
  29. return r;
  30. }
  31. static bool rt_mt6(const struct sk_buff *skb, struct xt_action_param *par)
  32. {
  33. struct ipv6_rt_hdr _route;
  34. const struct ipv6_rt_hdr *rh;
  35. const struct ip6t_rt *rtinfo = par->matchinfo;
  36. unsigned int temp;
  37. unsigned int ptr;
  38. unsigned int hdrlen = 0;
  39. bool ret = false;
  40. struct in6_addr _addr;
  41. const struct in6_addr *ap;
  42. int err;
  43. err = ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL);
  44. if (err < 0) {
  45. if (err != -ENOENT)
  46. par->hotdrop = true;
  47. return false;
  48. }
  49. rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route);
  50. if (rh == NULL) {
  51. par->hotdrop = true;
  52. return false;
  53. }
  54. hdrlen = ipv6_optlen(rh);
  55. if (skb->len - ptr < hdrlen) {
  56. return false;
  57. }
  58. pr_debug("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen);
  59. pr_debug("TYPE %04X ", rh->type);
  60. pr_debug("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left);
  61. pr_debug("IPv6 RT segsleft %02X ",
  62. segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
  63. rh->segments_left,
  64. !!(rtinfo->invflags & IP6T_RT_INV_SGS)));
  65. pr_debug("type %02X %02X %02X ",
  66. rtinfo->rt_type, rh->type,
  67. (!(rtinfo->flags & IP6T_RT_TYP) ||
  68. ((rtinfo->rt_type == rh->type) ^
  69. !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
  70. pr_debug("len %02X %04X %02X ",
  71. rtinfo->hdrlen, hdrlen,
  72. !(rtinfo->flags & IP6T_RT_LEN) ||
  73. ((rtinfo->hdrlen == hdrlen) ^
  74. !!(rtinfo->invflags & IP6T_RT_INV_LEN)));
  75. pr_debug("res %02X %02X %02X ",
  76. rtinfo->flags & IP6T_RT_RES,
  77. ((const struct rt0_hdr *)rh)->reserved,
  78. !((rtinfo->flags & IP6T_RT_RES) &&
  79. (((const struct rt0_hdr *)rh)->reserved)));
  80. ret = (rh != NULL) &&
  81. (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
  82. rh->segments_left,
  83. !!(rtinfo->invflags & IP6T_RT_INV_SGS))) &&
  84. (!(rtinfo->flags & IP6T_RT_LEN) ||
  85. ((rtinfo->hdrlen == hdrlen) ^
  86. !!(rtinfo->invflags & IP6T_RT_INV_LEN))) &&
  87. (!(rtinfo->flags & IP6T_RT_TYP) ||
  88. ((rtinfo->rt_type == rh->type) ^
  89. !!(rtinfo->invflags & IP6T_RT_INV_TYP)));
  90. if (ret && (rtinfo->flags & IP6T_RT_RES)) {
  91. const u_int32_t *rp;
  92. u_int32_t _reserved;
  93. rp = skb_header_pointer(skb,
  94. ptr + offsetof(struct rt0_hdr,
  95. reserved),
  96. sizeof(_reserved),
  97. &_reserved);
  98. ret = (*rp == 0);
  99. }
  100. pr_debug("#%d ", rtinfo->addrnr);
  101. if (!(rtinfo->flags & IP6T_RT_FST)) {
  102. return ret;
  103. } else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) {
  104. pr_debug("Not strict ");
  105. if (rtinfo->addrnr > (unsigned int)((hdrlen - 8) / 16)) {
  106. pr_debug("There isn't enough space\n");
  107. return false;
  108. } else {
  109. unsigned int i = 0;
  110. pr_debug("#%d ", rtinfo->addrnr);
  111. for (temp = 0;
  112. temp < (unsigned int)((hdrlen - 8) / 16);
  113. temp++) {
  114. ap = skb_header_pointer(skb,
  115. ptr
  116. + sizeof(struct rt0_hdr)
  117. + temp * sizeof(_addr),
  118. sizeof(_addr),
  119. &_addr);
  120. BUG_ON(ap == NULL);
  121. if (ipv6_addr_equal(ap, &rtinfo->addrs[i])) {
  122. pr_debug("i=%d temp=%d;\n", i, temp);
  123. i++;
  124. }
  125. if (i == rtinfo->addrnr)
  126. break;
  127. }
  128. pr_debug("i=%d #%d\n", i, rtinfo->addrnr);
  129. if (i == rtinfo->addrnr)
  130. return ret;
  131. else
  132. return false;
  133. }
  134. } else {
  135. pr_debug("Strict ");
  136. if (rtinfo->addrnr > (unsigned int)((hdrlen - 8) / 16)) {
  137. pr_debug("There isn't enough space\n");
  138. return false;
  139. } else {
  140. pr_debug("#%d ", rtinfo->addrnr);
  141. for (temp = 0; temp < rtinfo->addrnr; temp++) {
  142. ap = skb_header_pointer(skb,
  143. ptr
  144. + sizeof(struct rt0_hdr)
  145. + temp * sizeof(_addr),
  146. sizeof(_addr),
  147. &_addr);
  148. BUG_ON(ap == NULL);
  149. if (!ipv6_addr_equal(ap, &rtinfo->addrs[temp]))
  150. break;
  151. }
  152. pr_debug("temp=%d #%d\n", temp, rtinfo->addrnr);
  153. if (temp == rtinfo->addrnr &&
  154. temp == (unsigned int)((hdrlen - 8) / 16))
  155. return ret;
  156. else
  157. return false;
  158. }
  159. }
  160. return false;
  161. }
  162. static int rt_mt6_check(const struct xt_mtchk_param *par)
  163. {
  164. const struct ip6t_rt *rtinfo = par->matchinfo;
  165. if (rtinfo->invflags & ~IP6T_RT_INV_MASK) {
  166. pr_debug("unknown flags %X\n", rtinfo->invflags);
  167. return -EINVAL;
  168. }
  169. if ((rtinfo->flags & (IP6T_RT_RES | IP6T_RT_FST_MASK)) &&
  170. (!(rtinfo->flags & IP6T_RT_TYP) ||
  171. (rtinfo->rt_type != 0) ||
  172. (rtinfo->invflags & IP6T_RT_INV_TYP))) {
  173. pr_debug("`--rt-type 0' required before `--rt-0-*'");
  174. return -EINVAL;
  175. }
  176. return 0;
  177. }
  178. static struct xt_match rt_mt6_reg __read_mostly = {
  179. .name = "rt",
  180. .family = NFPROTO_IPV6,
  181. .match = rt_mt6,
  182. .matchsize = sizeof(struct ip6t_rt),
  183. .checkentry = rt_mt6_check,
  184. .me = THIS_MODULE,
  185. };
  186. static int __init rt_mt6_init(void)
  187. {
  188. return xt_register_match(&rt_mt6_reg);
  189. }
  190. static void __exit rt_mt6_exit(void)
  191. {
  192. xt_unregister_match(&rt_mt6_reg);
  193. }
  194. module_init(rt_mt6_init);
  195. module_exit(rt_mt6_exit);