ip6t_rt.c 5.8 KB

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