978b24660770dd3e49ca95f1657227180f29cf85
[openwrt.git] / target / linux / generic / patches-3.10 / 670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
1 --- a/include/net/netns/ipv6.h
2 +++ b/include/net/netns/ipv6.h
3 @@ -55,6 +55,7 @@ struct netns_ipv6 {
4         unsigned long            ip6_rt_last_gc;
5  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
6         struct rt6_info         *ip6_prohibit_entry;
7 +       struct rt6_info         *ip6_failed_policy_entry;
8         struct rt6_info         *ip6_blk_hole_entry;
9         struct fib6_table       *fib6_local_tbl;
10         struct fib_rules_ops    *fib6_rules_ops;
11 --- a/include/uapi/linux/fib_rules.h
12 +++ b/include/uapi/linux/fib_rules.h
13 @@ -64,6 +64,10 @@ enum {
14         FR_ACT_BLACKHOLE,       /* Drop without notification */
15         FR_ACT_UNREACHABLE,     /* Drop with ENETUNREACH */
16         FR_ACT_PROHIBIT,        /* Drop with EACCES */
17 +       FR_ACT_RES9,
18 +       FR_ACT_RES10,
19 +       FR_ACT_RES11,
20 +       FR_ACT_FAILED_POLICY,   /* Drop with EPERM */
21         __FR_ACT_MAX,
22  };
23  
24 --- a/include/uapi/linux/rtnetlink.h
25 +++ b/include/uapi/linux/rtnetlink.h
26 @@ -203,6 +203,7 @@ enum {
27         RTN_THROW,              /* Not in this table            */
28         RTN_NAT,                /* Translate this address       */
29         RTN_XRESOLVE,           /* Use external resolver        */
30 +       RTN_FAILED_POLICY,      /* Failed ingress/egress policy */
31         __RTN_MAX
32  };
33  
34 --- a/net/ipv4/fib_rules.c
35 +++ b/net/ipv4/fib_rules.c
36 @@ -84,6 +84,10 @@ static int fib4_rule_action(struct fib_r
37                 err = -EACCES;
38                 goto errout;
39  
40 +       case FR_ACT_FAILED_POLICY:
41 +               err = -EPERM;
42 +               goto errout;
43 +
44         case FR_ACT_BLACKHOLE:
45         default:
46                 err = -EINVAL;
47 --- a/net/ipv4/fib_semantics.c
48 +++ b/net/ipv4/fib_semantics.c
49 @@ -138,6 +138,10 @@ const struct fib_prop fib_props[RTN_MAX
50                 .error  = -EINVAL,
51                 .scope  = RT_SCOPE_NOWHERE,
52         },
53 +       [RTN_FAILED_POLICY] = {
54 +               .error  = -EPERM,
55 +               .scope  = RT_SCOPE_UNIVERSE,
56 +       },
57  };
58  
59  static void rt_fibinfo_free(struct rtable __rcu **rtp)
60 --- a/net/ipv4/fib_trie.c
61 +++ b/net/ipv4/fib_trie.c
62 @@ -2331,6 +2331,7 @@ static const char *const rtn_type_names[
63         [RTN_THROW] = "THROW",
64         [RTN_NAT] = "NAT",
65         [RTN_XRESOLVE] = "XRESOLVE",
66 +       [RTN_FAILED_POLICY] = "FAILED_POLICY",
67  };
68  
69  static inline const char *rtn_type(char *buf, size_t len, unsigned int t)
70 --- a/net/ipv4/ipmr.c
71 +++ b/net/ipv4/ipmr.c
72 @@ -181,6 +181,7 @@ static int ipmr_rule_action(struct fib_r
73         case FR_ACT_UNREACHABLE:
74                 return -ENETUNREACH;
75         case FR_ACT_PROHIBIT:
76 +       case FR_ACT_FAILED_POLICY:
77                 return -EACCES;
78         case FR_ACT_BLACKHOLE:
79         default:
80 --- a/net/ipv6/fib6_rules.c
81 +++ b/net/ipv6/fib6_rules.c
82 @@ -69,6 +69,9 @@ static int fib6_rule_action(struct fib_r
83         case FR_ACT_PROHIBIT:
84                 rt = net->ipv6.ip6_prohibit_entry;
85                 goto discard_pkt;
86 +       case FR_ACT_FAILED_POLICY:
87 +               rt = net->ipv6.ip6_failed_policy_entry;
88 +               goto discard_pkt;
89         }
90  
91         table = fib6_get_table(net, rule->table);
92 --- a/net/ipv6/ip6mr.c
93 +++ b/net/ipv6/ip6mr.c
94 @@ -166,6 +166,8 @@ static int ip6mr_rule_action(struct fib_
95                 return -ENETUNREACH;
96         case FR_ACT_PROHIBIT:
97                 return -EACCES;
98 +       case FR_ACT_FAILED_POLICY:
99 +               return -EPERM;
100         case FR_ACT_BLACKHOLE:
101         default:
102                 return -EINVAL;
103 --- a/net/ipv6/route.c
104 +++ b/net/ipv6/route.c
105 @@ -250,6 +250,24 @@ static const struct rt6_info ip6_prohibi
106         .rt6i_ref       = ATOMIC_INIT(1),
107  };
108  
109 +static int ip6_pkt_failed_policy(struct sk_buff *skb);
110 +static int ip6_pkt_failed_policy_out(struct sk_buff *skb);
111 +
112 +static const struct rt6_info ip6_failed_policy_entry_template = {
113 +       .dst = {
114 +               .__refcnt       = ATOMIC_INIT(1),
115 +               .__use          = 1,
116 +               .obsolete       = DST_OBSOLETE_FORCE_CHK,
117 +               .error          = -EPERM,
118 +               .input          = ip6_pkt_failed_policy,
119 +               .output         = ip6_pkt_failed_policy_out,
120 +       },
121 +       .rt6i_flags     = (RTF_REJECT | RTF_NONEXTHOP),
122 +       .rt6i_protocol  = RTPROT_KERNEL,
123 +       .rt6i_metric    = ~(u32) 0,
124 +       .rt6i_ref       = ATOMIC_INIT(1),
125 +};
126 +
127  static const struct rt6_info ip6_blk_hole_entry_template = {
128         .dst = {
129                 .__refcnt       = ATOMIC_INIT(1),
130 @@ -1509,6 +1527,11 @@ int ip6_route_add(struct fib6_config *cf
131                         rt->dst.output = ip6_pkt_prohibit_out;
132                         rt->dst.input = ip6_pkt_prohibit;
133                         break;
134 +               case RTN_FAILED_POLICY:
135 +                       rt->dst.error = -EPERM;
136 +                       rt->dst.output = ip6_pkt_failed_policy_out;
137 +                       rt->dst.input = ip6_pkt_failed_policy;
138 +                       break;
139                 case RTN_THROW:
140                 default:
141                         rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
142 @@ -2088,6 +2111,17 @@ static int ip6_pkt_prohibit_out(struct s
143         return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
144  }
145  
146 +static int ip6_pkt_failed_policy(struct sk_buff *skb)
147 +{
148 +       return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES);
149 +}
150 +
151 +static int ip6_pkt_failed_policy_out(struct sk_buff *skb)
152 +{
153 +       skb->dev = skb_dst(skb)->dev;
154 +       return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES);
155 +}
156 +
157  /*
158   *     Allocate a dst for local (unicast / anycast) address.
159   */
160 @@ -2290,7 +2324,8 @@ static int rtm_to_fib6_config(struct sk_
161         if (rtm->rtm_type == RTN_UNREACHABLE ||
162             rtm->rtm_type == RTN_BLACKHOLE ||
163             rtm->rtm_type == RTN_PROHIBIT ||
164 -           rtm->rtm_type == RTN_THROW)
165 +           rtm->rtm_type == RTN_THROW ||
166 +           rtm->rtm_type == RTN_FAILED_POLICY)
167                 cfg->fc_flags |= RTF_REJECT;
168  
169         if (rtm->rtm_type == RTN_LOCAL)
170 @@ -2492,6 +2527,9 @@ static int rt6_fill_node(struct net *net
171                 case -EACCES:
172                         rtm->rtm_type = RTN_PROHIBIT;
173                         break;
174 +               case -EPERM:
175 +                       rtm->rtm_type = RTN_FAILED_POLICY;
176 +                       break;
177                 case -EAGAIN:
178                         rtm->rtm_type = RTN_THROW;
179                         break;
180 @@ -2742,6 +2780,8 @@ static int ip6_route_dev_notify(struct n
181  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
182                 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
183                 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
184 +               net->ipv6.ip6_failed_policy_entry->dst.dev = dev;
185 +               net->ipv6.ip6_failed_policy_entry->rt6i_idev = in6_dev_get(dev);
186                 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
187                 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
188  #endif
189 @@ -3002,6 +3042,17 @@ static int __net_init ip6_route_net_init
190         net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
191         dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
192                          ip6_template_metrics, true);
193 +
194 +       net->ipv6.ip6_failed_policy_entry =
195 +               kmemdup(&ip6_failed_policy_entry_template,
196 +                       sizeof(*net->ipv6.ip6_failed_policy_entry), GFP_KERNEL);
197 +       if (!net->ipv6.ip6_failed_policy_entry)
198 +               goto out_ip6_blk_hole_entry;
199 +       net->ipv6.ip6_failed_policy_entry->dst.path =
200 +               (struct dst_entry *)net->ipv6.ip6_failed_policy_entry;
201 +       net->ipv6.ip6_failed_policy_entry->dst.ops = &net->ipv6.ip6_dst_ops;
202 +       dst_init_metrics(&net->ipv6.ip6_failed_policy_entry->dst,
203 +                        ip6_template_metrics, true);
204  #endif
205  
206         net->ipv6.sysctl.flush_delay = 0;
207 @@ -3020,6 +3071,8 @@ out:
208         return ret;
209  
210  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
211 +out_ip6_blk_hole_entry:
212 +       kfree(net->ipv6.ip6_blk_hole_entry);
213  out_ip6_prohibit_entry:
214         kfree(net->ipv6.ip6_prohibit_entry);
215  out_ip6_null_entry:
216 @@ -3037,6 +3090,7 @@ static void __net_exit ip6_route_net_exi
217  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
218         kfree(net->ipv6.ip6_prohibit_entry);
219         kfree(net->ipv6.ip6_blk_hole_entry);
220 +       kfree(net->ipv6.ip6_failed_policy_entry);
221  #endif
222         dst_entries_destroy(&net->ipv6.ip6_dst_ops);
223  }
224 @@ -3133,6 +3187,9 @@ int __init ip6_route_init(void)
225         init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
226         init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
227         init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
228 +       init_net.ipv6.ip6_failed_policy_entry->dst.dev = init_net.loopback_dev;
229 +       init_net.ipv6.ip6_failed_policy_entry->rt6i_idev =
230 +               in6_dev_get(init_net.loopback_dev);
231    #endif
232         ret = fib6_init();
233         if (ret)