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