670-ipv6-allow-rejecting-with-source-address-failed-policy.patch 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. From 1b5aaa4b16f6e6471ab1c07b38068197a1b4c395 Mon Sep 17 00:00:00 2001
  2. From: Jonas Gorski <jogo@openwrt.org>
  3. Date: Fri, 24 May 2013 14:40:54 +0200
  4. Subject: [PATCH 1/2] ipv6: allow rejecting with "source address failed policy"
  5. RFC6204 L-14 requires rejecting traffic from invalid addresses with
  6. ICMPv6 Destination Unreachable, Code 5 (Source address failed ingress/
  7. egress policy) on the LAN side, so add an appropriate rule for that.
  8. Signed-off-by: Jonas Gorski <jogo@openwrt.org>
  9. ---
  10. include/net/netns/ipv6.h | 1 +
  11. include/uapi/linux/fib_rules.h | 4 +++
  12. include/uapi/linux/rtnetlink.h | 1 +
  13. net/ipv4/fib_semantics.c | 4 +++
  14. net/ipv4/fib_trie.c | 1 +
  15. net/ipv4/ipmr.c | 1 +
  16. net/ipv6/fib6_rules.c | 4 +++
  17. net/ipv6/ip6mr.c | 2 ++
  18. net/ipv6/route.c | 58 +++++++++++++++++++++++++++++++++++++++++-
  19. 9 files changed, 75 insertions(+), 1 deletion(-)
  20. --- a/include/net/netns/ipv6.h
  21. +++ b/include/net/netns/ipv6.h
  22. @@ -59,6 +59,7 @@ struct netns_ipv6 {
  23. unsigned long ip6_rt_last_gc;
  24. #ifdef CONFIG_IPV6_MULTIPLE_TABLES
  25. struct rt6_info *ip6_prohibit_entry;
  26. + struct rt6_info *ip6_policy_failed_entry;
  27. struct rt6_info *ip6_blk_hole_entry;
  28. struct fib6_table *fib6_local_tbl;
  29. struct fib_rules_ops *fib6_rules_ops;
  30. --- a/include/uapi/linux/fib_rules.h
  31. +++ b/include/uapi/linux/fib_rules.h
  32. @@ -64,6 +64,10 @@ enum {
  33. FR_ACT_BLACKHOLE, /* Drop without notification */
  34. FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */
  35. FR_ACT_PROHIBIT, /* Drop with EACCES */
  36. + FR_ACT_RES9,
  37. + FR_ACT_RES10,
  38. + FR_ACT_RES11,
  39. + FR_ACT_POLICY_FAILED, /* Drop with EACCES */
  40. __FR_ACT_MAX,
  41. };
  42. --- a/include/uapi/linux/rtnetlink.h
  43. +++ b/include/uapi/linux/rtnetlink.h
  44. @@ -203,6 +203,7 @@ enum {
  45. RTN_THROW, /* Not in this table */
  46. RTN_NAT, /* Translate this address */
  47. RTN_XRESOLVE, /* Use external resolver */
  48. + RTN_POLICY_FAILED, /* Failed ingress/egress policy */
  49. __RTN_MAX
  50. };
  51. --- a/net/ipv4/fib_semantics.c
  52. +++ b/net/ipv4/fib_semantics.c
  53. @@ -138,6 +138,10 @@ const struct fib_prop fib_props[RTN_MAX
  54. .error = -EINVAL,
  55. .scope = RT_SCOPE_NOWHERE,
  56. },
  57. + [RTN_POLICY_FAILED] = {
  58. + .error = -EACCES,
  59. + .scope = RT_SCOPE_UNIVERSE,
  60. + },
  61. };
  62. static void rt_fibinfo_free(struct rtable __rcu **rtp)
  63. --- a/net/ipv4/fib_trie.c
  64. +++ b/net/ipv4/fib_trie.c
  65. @@ -2236,6 +2236,7 @@ static const char *const rtn_type_names[
  66. [RTN_THROW] = "THROW",
  67. [RTN_NAT] = "NAT",
  68. [RTN_XRESOLVE] = "XRESOLVE",
  69. + [RTN_POLICY_FAILED] = "POLICY_FAILED",
  70. };
  71. static inline const char *rtn_type(char *buf, size_t len, unsigned int t)
  72. --- a/net/ipv4/ipmr.c
  73. +++ b/net/ipv4/ipmr.c
  74. @@ -184,6 +184,7 @@ static int ipmr_rule_action(struct fib_r
  75. case FR_ACT_UNREACHABLE:
  76. return -ENETUNREACH;
  77. case FR_ACT_PROHIBIT:
  78. + case FR_ACT_POLICY_FAILED:
  79. return -EACCES;
  80. case FR_ACT_BLACKHOLE:
  81. default:
  82. --- a/net/ipv6/fib6_rules.c
  83. +++ b/net/ipv6/fib6_rules.c
  84. @@ -73,6 +73,10 @@ static int fib6_rule_action(struct fib_r
  85. err = -EACCES;
  86. rt = net->ipv6.ip6_prohibit_entry;
  87. goto discard_pkt;
  88. + case FR_ACT_POLICY_FAILED:
  89. + err = -EACCES;
  90. + rt = net->ipv6.ip6_policy_failed_entry;
  91. + goto discard_pkt;
  92. }
  93. table = fib6_get_table(net, rule->table);
  94. --- a/net/ipv6/ip6mr.c
  95. +++ b/net/ipv6/ip6mr.c
  96. @@ -169,6 +169,8 @@ static int ip6mr_rule_action(struct fib_
  97. return -ENETUNREACH;
  98. case FR_ACT_PROHIBIT:
  99. return -EACCES;
  100. + case FR_ACT_POLICY_FAILED:
  101. + return -EACCES;
  102. case FR_ACT_BLACKHOLE:
  103. default:
  104. return -EINVAL;
  105. --- a/net/ipv6/route.c
  106. +++ b/net/ipv6/route.c
  107. @@ -87,6 +87,8 @@ static int ip6_pkt_discard(struct sk_bu
  108. static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb);
  109. static int ip6_pkt_prohibit(struct sk_buff *skb);
  110. static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb);
  111. +static int ip6_pkt_policy_failed(struct sk_buff *skb);
  112. +static int ip6_pkt_policy_failed_out(struct sock *sk, struct sk_buff *skb);
  113. static void ip6_link_failure(struct sk_buff *skb);
  114. static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
  115. struct sk_buff *skb, u32 mtu);
  116. @@ -283,6 +285,21 @@ static const struct rt6_info ip6_prohibi
  117. .rt6i_ref = ATOMIC_INIT(1),
  118. };
  119. +static const struct rt6_info ip6_policy_failed_entry_template = {
  120. + .dst = {
  121. + .__refcnt = ATOMIC_INIT(1),
  122. + .__use = 1,
  123. + .obsolete = DST_OBSOLETE_FORCE_CHK,
  124. + .error = -EACCES,
  125. + .input = ip6_pkt_policy_failed,
  126. + .output = ip6_pkt_policy_failed_out,
  127. + },
  128. + .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
  129. + .rt6i_protocol = RTPROT_KERNEL,
  130. + .rt6i_metric = ~(u32) 0,
  131. + .rt6i_ref = ATOMIC_INIT(1),
  132. +};
  133. +
  134. static const struct rt6_info ip6_blk_hole_entry_template = {
  135. .dst = {
  136. .__refcnt = ATOMIC_INIT(1),
  137. @@ -1579,6 +1596,11 @@ int ip6_route_add(struct fib6_config *cf
  138. rt->dst.output = ip6_pkt_prohibit_out;
  139. rt->dst.input = ip6_pkt_prohibit;
  140. break;
  141. + case RTN_POLICY_FAILED:
  142. + rt->dst.error = -EACCES;
  143. + rt->dst.output = ip6_pkt_policy_failed_out;
  144. + rt->dst.input = ip6_pkt_policy_failed;
  145. + break;
  146. case RTN_THROW:
  147. default:
  148. rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
  149. @@ -2142,6 +2164,17 @@ static int ip6_pkt_prohibit_out(struct s
  150. return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
  151. }
  152. +static int ip6_pkt_policy_failed(struct sk_buff *skb)
  153. +{
  154. + return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES);
  155. +}
  156. +
  157. +static int ip6_pkt_policy_failed_out(struct sock *sk, struct sk_buff *skb)
  158. +{
  159. + skb->dev = skb_dst(skb)->dev;
  160. + return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES);
  161. +}
  162. +
  163. /*
  164. * Allocate a dst for local (unicast / anycast) address.
  165. */
  166. @@ -2368,7 +2401,8 @@ static int rtm_to_fib6_config(struct sk_
  167. if (rtm->rtm_type == RTN_UNREACHABLE ||
  168. rtm->rtm_type == RTN_BLACKHOLE ||
  169. rtm->rtm_type == RTN_PROHIBIT ||
  170. - rtm->rtm_type == RTN_THROW)
  171. + rtm->rtm_type == RTN_THROW ||
  172. + rtm->rtm_type == RTN_POLICY_FAILED)
  173. cfg->fc_flags |= RTF_REJECT;
  174. if (rtm->rtm_type == RTN_LOCAL)
  175. @@ -2570,6 +2604,9 @@ static int rt6_fill_node(struct net *net
  176. case -EACCES:
  177. rtm->rtm_type = RTN_PROHIBIT;
  178. break;
  179. + case -EPERM:
  180. + rtm->rtm_type = RTN_POLICY_FAILED;
  181. + break;
  182. case -EAGAIN:
  183. rtm->rtm_type = RTN_THROW;
  184. break;
  185. @@ -2828,6 +2865,8 @@ static int ip6_route_dev_notify(struct n
  186. #ifdef CONFIG_IPV6_MULTIPLE_TABLES
  187. net->ipv6.ip6_prohibit_entry->dst.dev = dev;
  188. net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
  189. + net->ipv6.ip6_policy_failed_entry->dst.dev = dev;
  190. + net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev);
  191. net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
  192. net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
  193. #endif
  194. @@ -3054,6 +3093,17 @@ static int __net_init ip6_route_net_init
  195. net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
  196. dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
  197. ip6_template_metrics, true);
  198. +
  199. + net->ipv6.ip6_policy_failed_entry =
  200. + kmemdup(&ip6_policy_failed_entry_template,
  201. + sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL);
  202. + if (!net->ipv6.ip6_policy_failed_entry)
  203. + goto out_ip6_blk_hole_entry;
  204. + net->ipv6.ip6_policy_failed_entry->dst.path =
  205. + (struct dst_entry *)net->ipv6.ip6_policy_failed_entry;
  206. + net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops;
  207. + dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst,
  208. + ip6_template_metrics, true);
  209. #endif
  210. net->ipv6.sysctl.flush_delay = 0;
  211. @@ -3072,6 +3122,8 @@ out:
  212. return ret;
  213. #ifdef CONFIG_IPV6_MULTIPLE_TABLES
  214. +out_ip6_blk_hole_entry:
  215. + kfree(net->ipv6.ip6_blk_hole_entry);
  216. out_ip6_prohibit_entry:
  217. kfree(net->ipv6.ip6_prohibit_entry);
  218. out_ip6_null_entry:
  219. @@ -3089,6 +3141,7 @@ static void __net_exit ip6_route_net_exi
  220. #ifdef CONFIG_IPV6_MULTIPLE_TABLES
  221. kfree(net->ipv6.ip6_prohibit_entry);
  222. kfree(net->ipv6.ip6_blk_hole_entry);
  223. + kfree(net->ipv6.ip6_policy_failed_entry);
  224. #endif
  225. dst_entries_destroy(&net->ipv6.ip6_dst_ops);
  226. }
  227. @@ -3162,6 +3215,9 @@ void __init ip6_route_init_special_entri
  228. init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
  229. init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
  230. init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
  231. + init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev;
  232. + init_net.ipv6.ip6_policy_failed_entry->rt6i_idev =
  233. + in6_dev_get(init_net.loopback_dev);
  234. #endif
  235. }