]>
Commit | Line | Data |
---|---|---|
2581e8f3 | 1 | diff -ur v2.6.7-before-nf_reroute/linux/include/linux/netfilter_ipv4/ip_nat.h linux/include/linux/netfilter_ipv4/ip_nat.h |
2 | --- v2.6.7-before-nf_reroute/linux/include/linux/netfilter_ipv4/ip_nat.h 2004-03-11 23:48:04.000000000 +0200 | |
3 | +++ linux/include/linux/netfilter_ipv4/ip_nat.h 2004-06-17 01:02:46.811977384 +0300 | |
4 | @@ -121,5 +121,13 @@ | |
5 | extern u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv, | |
6 | u_int32_t newval, | |
7 | u_int16_t oldcheck); | |
8 | + | |
9 | +/* Call input routing for SNAT-ed traffic */ | |
10 | +extern unsigned int ip_nat_route_input(unsigned int hooknum, | |
11 | + struct sk_buff **pskb, | |
12 | + const struct net_device *in, | |
13 | + const struct net_device *out, | |
14 | + int (*okfn)(struct sk_buff *)); | |
15 | + | |
16 | #endif /*__KERNEL__*/ | |
17 | #endif | |
18 | diff -ur v2.6.7-before-nf_reroute/linux/include/net/flow.h linux/include/net/flow.h | |
19 | --- v2.6.7-before-nf_reroute/linux/include/net/flow.h 2004-04-04 09:43:36.000000000 +0300 | |
20 | +++ linux/include/net/flow.h 2004-06-17 01:02:46.812977232 +0300 | |
21 | @@ -19,6 +19,8 @@ | |
22 | __u32 daddr; | |
23 | __u32 saddr; | |
24 | __u32 fwmark; | |
25 | + __u32 lsrc; | |
26 | + __u32 gw; | |
27 | __u8 tos; | |
28 | __u8 scope; | |
29 | } ip4_u; | |
30 | @@ -46,6 +48,8 @@ | |
31 | #define fl4_dst nl_u.ip4_u.daddr | |
32 | #define fl4_src nl_u.ip4_u.saddr | |
33 | #define fl4_fwmark nl_u.ip4_u.fwmark | |
34 | +#define fl4_lsrc nl_u.ip4_u.lsrc | |
35 | +#define fl4_gw nl_u.ip4_u.gw | |
36 | #define fl4_tos nl_u.ip4_u.tos | |
37 | #define fl4_scope nl_u.ip4_u.scope | |
38 | ||
39 | diff -ur v2.6.7-before-nf_reroute/linux/include/net/route.h linux/include/net/route.h | |
40 | --- v2.6.7-before-nf_reroute/linux/include/net/route.h 2004-06-16 23:54:05.000000000 +0300 | |
41 | +++ linux/include/net/route.h 2004-06-17 01:02:46.812977232 +0300 | |
42 | @@ -124,6 +124,7 @@ | |
43 | extern int ip_route_output_key(struct rtable **, struct flowi *flp); | |
44 | extern int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags); | |
45 | extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin); | |
46 | +extern int ip_route_input_lookup(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin, u32 lsrc); | |
47 | extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu); | |
48 | extern void ip_rt_send_redirect(struct sk_buff *skb); | |
49 | ||
50 | diff -ur v2.6.7-before-nf_reroute/linux/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c | |
51 | --- v2.6.7-before-nf_reroute/linux/net/ipv4/fib_hash.c 2004-06-17 01:01:41.000000000 +0300 | |
52 | +++ linux/net/ipv4/fib_hash.c 2004-06-17 01:02:46.813977080 +0300 | |
53 | @@ -352,6 +352,9 @@ | |
54 | for (nhsel = 0, nh = fi->fib_nh; nhsel < fi->fib_nhs; nh++, nhsel++) { | |
55 | if (flp->oif && flp->oif != nh->nh_oif) | |
56 | continue; | |
57 | + if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw && nh->nh_gw && | |
58 | + nh->nh_scope == RT_SCOPE_LINK) | |
59 | + continue; | |
60 | if (nh->nh_flags & RTNH_F_DEAD) | |
61 | continue; | |
62 | ||
63 | diff -ur v2.6.7-before-nf_reroute/linux/net/ipv4/fib_semantics.c linux/net/ipv4/fib_semantics.c | |
64 | --- v2.6.7-before-nf_reroute/linux/net/ipv4/fib_semantics.c 2004-06-17 01:01:41.000000000 +0300 | |
65 | +++ linux/net/ipv4/fib_semantics.c 2004-06-17 01:02:46.814976928 +0300 | |
66 | @@ -674,8 +674,12 @@ | |
67 | for_nexthops(fi) { | |
68 | if (nh->nh_flags&RTNH_F_DEAD) | |
69 | continue; | |
70 | - if (!flp->oif || flp->oif == nh->nh_oif) | |
71 | - break; | |
72 | + if (flp->oif && flp->oif != nh->nh_oif) | |
73 | + continue; | |
74 | + if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw && | |
75 | + nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK) | |
76 | + continue; | |
77 | + break; | |
78 | } | |
79 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | |
80 | if (nhsel < fi->fib_nhs) { | |
81 | @@ -1068,6 +1072,9 @@ | |
82 | change_nexthops(fi) { | |
83 | if (flp->oif != nh->nh_oif) | |
84 | continue; | |
85 | + if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw && | |
86 | + nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK) | |
87 | + continue; | |
88 | if (!(nh->nh_flags&RTNH_F_BADSTATE)) { | |
89 | if (nh->nh_power > w) { | |
90 | w = nh->nh_power; | |
91 | @@ -1126,11 +1133,14 @@ | |
92 | ||
93 | for_nexthops(fi) { | |
94 | if (!(nh->nh_flags&RTNH_F_DEAD)) { | |
95 | - if (!flp->oif || flp->oif == nh->nh_oif) { | |
96 | - spin_unlock_bh(&fib_multipath_lock); | |
97 | - res->nh_sel = nhsel; | |
98 | - return; | |
99 | - } | |
100 | + if (flp->oif && flp->oif != nh->nh_oif) | |
101 | + continue; | |
102 | + if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw && | |
103 | + nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK) | |
104 | + continue; | |
105 | + spin_unlock_bh(&fib_multipath_lock); | |
106 | + res->nh_sel = nhsel; | |
107 | + return; | |
108 | } | |
109 | } endfor_nexthops(fi); | |
110 | ||
111 | diff -ur v2.6.7-before-nf_reroute/linux/net/ipv4/netfilter/ip_fw_compat_masq.c linux/net/ipv4/netfilter/ip_fw_compat_masq.c | |
112 | --- v2.6.7-before-nf_reroute/linux/net/ipv4/netfilter/ip_fw_compat_masq.c 2004-04-04 09:43:37.000000000 +0300 | |
113 | +++ linux/net/ipv4/netfilter/ip_fw_compat_masq.c 2004-06-17 01:02:46.814976928 +0300 | |
114 | @@ -44,15 +44,20 @@ | |
115 | unsigned int | |
116 | do_masquerade(struct sk_buff **pskb, const struct net_device *dev) | |
117 | { | |
118 | + struct iphdr *iph = (*pskb)->nh.iph; | |
119 | struct ip_nat_info *info; | |
120 | enum ip_conntrack_info ctinfo; | |
121 | struct ip_conntrack *ct; | |
122 | unsigned int ret; | |
123 | + struct rtable *rt, *skb_rt; | |
124 | + struct net_device *skb_dev; | |
125 | + __u32 saddr; | |
126 | + int new; | |
127 | ||
128 | /* Sorry, only ICMP, TCP and UDP. */ | |
129 | - if ((*pskb)->nh.iph->protocol != IPPROTO_ICMP | |
130 | - && (*pskb)->nh.iph->protocol != IPPROTO_TCP | |
131 | - && (*pskb)->nh.iph->protocol != IPPROTO_UDP) | |
132 | + if (iph->protocol != IPPROTO_ICMP | |
133 | + && iph->protocol != IPPROTO_TCP | |
134 | + && iph->protocol != IPPROTO_UDP) | |
135 | return NF_DROP; | |
136 | ||
137 | /* Feed it to connection tracking; in fact we're in NF_IP_FORWARD, | |
138 | @@ -71,23 +76,30 @@ | |
139 | } | |
140 | ||
141 | info = &ct->nat.info; | |
142 | + iph = (*pskb)->nh.iph; | |
143 | + saddr = iph->saddr; | |
144 | + new = 0; | |
145 | ||
146 | WRITE_LOCK(&ip_nat_lock); | |
147 | /* Setup the masquerade, if not already */ | |
148 | if (!info->initialized) { | |
149 | u_int32_t newsrc; | |
150 | struct flowi fl = { .nl_u = { .ip4_u = { .daddr = (*pskb)->nh.iph->daddr } } }; | |
151 | - struct rtable *rt; | |
152 | struct ip_nat_multi_range range; | |
153 | ||
154 | + skb_rt = (struct rtable *) (*pskb)->dst; | |
155 | + skb_dev = skb_rt->u.dst.dev; | |
156 | /* Pass 0 instead of saddr, since it's going to be changed | |
157 | anyway. */ | |
158 | + fl.fl4_tos = RT_TOS(iph->tos); | |
159 | + fl.fl4_gw = skb_dev? skb_rt->rt_gateway : 0; | |
160 | + fl.oif = skb_dev? skb_dev->ifindex : 0; | |
161 | if (ip_route_output_key(&rt, &fl) != 0) { | |
162 | + WRITE_UNLOCK(&ip_nat_lock); | |
163 | DEBUGP("ipnat_rule_masquerade: Can't reroute.\n"); | |
164 | return NF_DROP; | |
165 | } | |
166 | - newsrc = inet_select_addr(rt->u.dst.dev, rt->rt_gateway, | |
167 | - RT_SCOPE_UNIVERSE); | |
168 | + newsrc = rt->rt_src; | |
169 | ip_rt_put(rt); | |
170 | range = ((struct ip_nat_multi_range) | |
171 | { 1, | |
172 | @@ -100,11 +112,36 @@ | |
173 | WRITE_UNLOCK(&ip_nat_lock); | |
174 | return ret; | |
175 | } | |
176 | + new = 1; | |
177 | } else | |
178 | DEBUGP("Masquerading already done on this conn.\n"); | |
179 | WRITE_UNLOCK(&ip_nat_lock); | |
180 | ||
181 | - return do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb); | |
182 | + ret = do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb); | |
183 | + if (ret != NF_ACCEPT || saddr == (*pskb)->nh.iph->saddr || new) | |
184 | + return ret; | |
185 | + | |
186 | + iph = (*pskb)->nh.iph; | |
187 | + { | |
188 | + struct flowi fl = { .nl_u = { .ip4_u = | |
189 | + { .saddr = iph->saddr, | |
190 | + .daddr = iph->daddr, | |
191 | + .tos = RT_TOS(iph->tos) } } }; | |
192 | + if (ip_route_output_key(&rt, &fl) != 0) | |
193 | + return NF_DROP; | |
194 | + } | |
195 | + skb_rt = (struct rtable *) (*pskb)->dst; | |
196 | + skb_dev = skb_rt->u.dst.dev; | |
197 | + if (skb_dev != rt->u.dst.dev || rt->rt_gateway != skb_rt->rt_gateway) { | |
198 | + if (skb_dev != rt->u.dst.dev) { | |
199 | + /* TODO: check the new mtu and reply FRAG_NEEDED */ | |
200 | + } | |
201 | + dst_release((*pskb)->dst); | |
202 | + (*pskb)->dst = &rt->u.dst; | |
203 | + } else { | |
204 | + ip_rt_put(rt); | |
205 | + } | |
206 | + return NF_ACCEPT; | |
207 | } | |
208 | ||
209 | void | |
210 | diff -ur v2.6.7-before-nf_reroute/linux/net/ipv4/netfilter/ip_nat_core.c linux/net/ipv4/netfilter/ip_nat_core.c | |
211 | --- v2.6.7-before-nf_reroute/linux/net/ipv4/netfilter/ip_nat_core.c 2004-05-11 02:09:54.000000000 +0300 | |
212 | +++ linux/net/ipv4/netfilter/ip_nat_core.c 2004-06-17 01:02:46.815976776 +0300 | |
213 | @@ -987,6 +987,60 @@ | |
214 | return 0; | |
215 | } | |
216 | ||
217 | +unsigned int | |
218 | +ip_nat_route_input(unsigned int hooknum, | |
219 | + struct sk_buff **pskb, | |
220 | + const struct net_device *in, | |
221 | + const struct net_device *out, | |
222 | + int (*okfn)(struct sk_buff *)) | |
223 | +{ | |
224 | + struct sk_buff *skb = *pskb; | |
225 | + struct iphdr *iph; | |
226 | + struct ip_conntrack *ct; | |
227 | + enum ip_conntrack_info ctinfo; | |
228 | + struct ip_nat_info *info; | |
229 | + enum ip_conntrack_dir dir; | |
230 | + __u32 saddr; | |
231 | + int i; | |
232 | + | |
233 | + if (!(ct = ip_conntrack_get(skb, &ctinfo))) | |
234 | + return NF_ACCEPT; | |
235 | + | |
236 | + info = &ct->nat.info; | |
237 | + if (!info->initialized) | |
238 | + return NF_ACCEPT; | |
239 | + | |
240 | + if (skb->dst) | |
241 | + return NF_ACCEPT; | |
242 | + | |
243 | + if (skb->len < sizeof(struct iphdr)) | |
244 | + return NF_ACCEPT; | |
245 | + | |
246 | + iph = skb->nh.iph; | |
247 | + saddr = iph->saddr; | |
248 | + hooknum = NF_IP_POST_ROUTING; | |
249 | + dir = CTINFO2DIR(ctinfo); | |
250 | + | |
251 | + READ_LOCK(&ip_nat_lock); | |
252 | + for (i = 0; i < info->num_manips; i++) { | |
253 | + if (info->manips[i].direction == dir | |
254 | + && info->manips[i].hooknum == hooknum | |
255 | + && info->manips[i].maniptype == IP_NAT_MANIP_SRC) { | |
256 | + saddr = info->manips[i].manip.ip; | |
257 | + } | |
258 | + } | |
259 | + READ_UNLOCK(&ip_nat_lock); | |
260 | + | |
261 | + if (saddr == iph->saddr) | |
262 | + return NF_ACCEPT; | |
263 | + | |
264 | + if (ip_route_input_lookup(skb, iph->daddr, iph->saddr, iph->tos, | |
265 | + skb->dev, saddr)) | |
266 | + return NF_DROP; | |
267 | + | |
268 | + return NF_ACCEPT; | |
269 | +} | |
270 | + | |
271 | int __init ip_nat_init(void) | |
272 | { | |
273 | size_t i; | |
274 | diff -ur v2.6.7-before-nf_reroute/linux/net/ipv4/netfilter/ip_nat_standalone.c linux/net/ipv4/netfilter/ip_nat_standalone.c | |
275 | --- v2.6.7-before-nf_reroute/linux/net/ipv4/netfilter/ip_nat_standalone.c 2004-06-16 23:54:06.000000000 +0300 | |
276 | +++ linux/net/ipv4/netfilter/ip_nat_standalone.c 2004-06-17 01:02:46.816976624 +0300 | |
277 | @@ -247,6 +247,14 @@ | |
278 | .priority = NF_IP_PRI_NAT_DST, | |
279 | }; | |
280 | ||
281 | +/* Before routing, route before mangling */ | |
282 | +static struct nf_hook_ops ip_nat_inr_ops = { | |
283 | + .hook = ip_nat_route_input, | |
284 | + .pf = PF_INET, | |
285 | + .hooknum = NF_IP_PRE_ROUTING, | |
286 | + .priority = NF_IP_PRI_LAST-1, | |
287 | +}; | |
288 | + | |
289 | /* After packet filtering, change source */ | |
290 | static struct nf_hook_ops ip_nat_out_ops = { | |
291 | .hook = ip_nat_out, | |
292 | @@ -331,10 +339,15 @@ | |
293 | printk("ip_nat_init: can't register in hook.\n"); | |
294 | goto cleanup_nat; | |
295 | } | |
296 | + ret = nf_register_hook(&ip_nat_inr_ops); | |
297 | + if (ret < 0) { | |
298 | + printk("ip_nat_init: can't register inr hook.\n"); | |
299 | + goto cleanup_inops; | |
300 | + } | |
301 | ret = nf_register_hook(&ip_nat_out_ops); | |
302 | if (ret < 0) { | |
303 | printk("ip_nat_init: can't register out hook.\n"); | |
304 | - goto cleanup_inops; | |
305 | + goto cleanup_inrops; | |
306 | } | |
307 | #ifdef CONFIG_IP_NF_NAT_LOCAL | |
308 | ret = nf_register_hook(&ip_nat_local_out_ops); | |
309 | @@ -358,6 +371,8 @@ | |
310 | cleanup_outops: | |
311 | #endif | |
312 | nf_unregister_hook(&ip_nat_out_ops); | |
313 | + cleanup_inrops: | |
314 | + nf_unregister_hook(&ip_nat_inr_ops); | |
315 | cleanup_inops: | |
316 | nf_unregister_hook(&ip_nat_in_ops); | |
317 | cleanup_nat: | |
318 | diff -ur v2.6.7-before-nf_reroute/linux/net/ipv4/netfilter/ipt_MASQUERADE.c linux/net/ipv4/netfilter/ipt_MASQUERADE.c | |
319 | --- v2.6.7-before-nf_reroute/linux/net/ipv4/netfilter/ipt_MASQUERADE.c 2004-05-11 02:09:54.000000000 +0300 | |
320 | +++ linux/net/ipv4/netfilter/ipt_MASQUERADE.c 2004-06-17 01:02:46.816976624 +0300 | |
321 | @@ -101,10 +101,12 @@ | |
322 | { .daddr = (*pskb)->nh.iph->daddr, | |
323 | .tos = (RT_TOS((*pskb)->nh.iph->tos) | | |
324 | RTO_CONN), | |
325 | + .gw = ((struct rtable *) (*pskb)->dst)->rt_gateway, | |
326 | #ifdef CONFIG_IP_ROUTE_FWMARK | |
327 | .fwmark = (*pskb)->nfmark | |
328 | #endif | |
329 | - } } }; | |
330 | + } }, | |
331 | + .oif = out->ifindex }; | |
332 | if (ip_route_output_key(&rt, &fl) != 0) { | |
333 | /* Funky routing can do this. */ | |
334 | if (net_ratelimit()) | |
335 | @@ -112,13 +114,6 @@ | |
336 | " No route: Rusty's brain broke!\n"); | |
337 | return NF_DROP; | |
338 | } | |
339 | - if (rt->u.dst.dev != out) { | |
340 | - if (net_ratelimit()) | |
341 | - printk("MASQUERADE:" | |
342 | - " Route sent us somewhere else.\n"); | |
343 | - ip_rt_put(rt); | |
344 | - return NF_DROP; | |
345 | - } | |
346 | } | |
347 | ||
348 | newsrc = rt->rt_src; | |
349 | diff -ur v2.6.7-before-nf_reroute/linux/net/ipv4/route.c linux/net/ipv4/route.c | |
350 | --- v2.6.7-before-nf_reroute/linux/net/ipv4/route.c 2004-06-17 01:01:41.000000000 +0300 | |
351 | +++ linux/net/ipv4/route.c 2004-06-17 01:03:04.388305376 +0300 | |
352 | @@ -1055,6 +1055,7 @@ | |
353 | ||
354 | /* Gateway is different ... */ | |
355 | rt->rt_gateway = new_gw; | |
356 | + if (rt->fl.fl4_gw) rt->fl.fl4_gw = new_gw; | |
357 | ||
358 | /* Redirect received -> path was valid */ | |
359 | dst_confirm(&rth->u.dst); | |
360 | @@ -1496,6 +1497,7 @@ | |
361 | rth->fl.fl4_fwmark= skb->nfmark; | |
362 | #endif | |
363 | rth->fl.fl4_src = saddr; | |
364 | + rth->fl.fl4_lsrc = 0; | |
365 | rth->rt_src = saddr; | |
366 | #ifdef CONFIG_IP_ROUTE_NAT | |
367 | rth->rt_dst_map = daddr; | |
368 | @@ -1510,6 +1512,7 @@ | |
369 | dev_hold(rth->u.dst.dev); | |
370 | rth->idev = in_dev_get(rth->u.dst.dev); | |
371 | rth->fl.oif = 0; | |
372 | + rth->fl.fl4_gw = 0; | |
373 | rth->rt_gateway = daddr; | |
374 | rth->rt_spec_dst= spec_dst; | |
375 | rth->rt_type = RTN_MULTICAST; | |
376 | @@ -1549,21 +1552,21 @@ | |
377 | */ | |
378 | ||
379 | static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr, | |
380 | - u8 tos, struct net_device *dev) | |
381 | + u8 tos, struct net_device *dev, u32 lsrc) | |
382 | { | |
383 | struct fib_result res; | |
384 | struct in_device *in_dev = in_dev_get(dev); | |
385 | struct in_device *out_dev = NULL; | |
386 | struct flowi fl = { .nl_u = { .ip4_u = | |
387 | { .daddr = daddr, | |
388 | - .saddr = saddr, | |
389 | + .saddr = lsrc? : saddr, | |
390 | .tos = tos, | |
391 | .scope = RT_SCOPE_UNIVERSE, | |
392 | #ifdef CONFIG_IP_ROUTE_FWMARK | |
393 | .fwmark = skb->nfmark | |
394 | #endif | |
395 | } }, | |
396 | - .iif = dev->ifindex }; | |
397 | + .iif = lsrc? loopback_dev.ifindex : dev->ifindex }; | |
398 | unsigned flags = 0; | |
399 | u32 itag = 0; | |
400 | struct rtable * rth; | |
401 | @@ -1577,7 +1580,7 @@ | |
402 | if (!in_dev) | |
403 | goto out; | |
404 | ||
405 | - hash = rt_hash_code(daddr, saddr ^ (fl.iif << 5), tos); | |
406 | + hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5), tos); | |
407 | ||
408 | /* Check for the most weird martians, which can be not detected | |
409 | by fib_lookup. | |
410 | @@ -1598,6 +1601,12 @@ | |
411 | if (BADCLASS(daddr) || ZERONET(daddr) || LOOPBACK(daddr)) | |
412 | goto martian_destination; | |
413 | ||
414 | + if (lsrc) { | |
415 | + if (MULTICAST(lsrc) || BADCLASS(lsrc) || | |
416 | + ZERONET(lsrc) || LOOPBACK(lsrc)) | |
417 | + goto e_inval; | |
418 | + } | |
419 | + | |
420 | /* | |
421 | * Now we are ready to route packet. | |
422 | */ | |
423 | @@ -1607,6 +1616,10 @@ | |
424 | goto no_route; | |
425 | } | |
426 | free_res = 1; | |
427 | + if (lsrc && res.type != RTN_UNICAST && res.type != RTN_NAT) | |
428 | + goto e_inval; | |
429 | + fl.iif = dev->ifindex; | |
430 | + fl.fl4_src = saddr; | |
431 | ||
432 | RT_CACHE_STAT_INC(in_slow_tot); | |
433 | ||
434 | @@ -1617,7 +1630,7 @@ | |
435 | ||
436 | if (1) { | |
437 | u32 src_map = saddr; | |
438 | - if (res.r) | |
439 | + if (res.r && !lsrc) | |
440 | src_map = fib_rules_policy(saddr, &res, &flags); | |
441 | ||
442 | if (res.type == RTN_NAT) { | |
443 | @@ -1678,6 +1691,7 @@ | |
444 | flags |= RTCF_DIRECTSRC; | |
445 | ||
446 | if (out_dev == in_dev && err && !(flags & (RTCF_NAT | RTCF_MASQ)) && | |
447 | + !lsrc && | |
448 | (IN_DEV_SHARED_MEDIA(out_dev) || | |
449 | inet_addr_onlink(out_dev, saddr, FIB_RES_GW(res)))) | |
450 | flags |= RTCF_DOREDIRECT; | |
451 | @@ -1708,6 +1722,7 @@ | |
452 | #endif | |
453 | rth->fl.fl4_src = saddr; | |
454 | rth->rt_src = saddr; | |
455 | + rth->fl.fl4_lsrc = lsrc; | |
456 | rth->rt_gateway = daddr; | |
457 | #ifdef CONFIG_IP_ROUTE_NAT | |
458 | rth->rt_src_map = fl.fl4_src; | |
459 | @@ -1721,6 +1736,7 @@ | |
460 | dev_hold(rth->u.dst.dev); | |
461 | rth->idev = in_dev_get(rth->u.dst.dev); | |
462 | rth->fl.oif = 0; | |
463 | + rth->fl.fl4_gw = 0; | |
464 | rth->rt_spec_dst= spec_dst; | |
465 | ||
466 | rth->u.dst.input = ip_forward; | |
467 | @@ -1731,7 +1747,8 @@ | |
468 | rth->rt_flags = flags; | |
469 | ||
470 | #ifdef CONFIG_NET_FASTROUTE | |
471 | - if (netdev_fastroute && !(flags&(RTCF_NAT|RTCF_MASQ|RTCF_DOREDIRECT))) { | |
472 | + if (netdev_fastroute && !(flags&(RTCF_NAT|RTCF_MASQ|RTCF_DOREDIRECT)) && | |
473 | + !lsrc) { | |
474 | struct net_device *odev = rth->u.dst.dev; | |
475 | if (odev != dev && | |
476 | dev->accept_fastpath && | |
477 | @@ -1754,6 +1771,8 @@ | |
478 | brd_input: | |
479 | if (skb->protocol != htons(ETH_P_IP)) | |
480 | goto e_inval; | |
481 | + if (lsrc) | |
482 | + goto e_inval; | |
483 | ||
484 | if (ZERONET(saddr)) | |
485 | spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); | |
486 | @@ -1800,6 +1819,7 @@ | |
487 | rth->u.dst.dev = &loopback_dev; | |
488 | dev_hold(rth->u.dst.dev); | |
489 | rth->idev = in_dev_get(rth->u.dst.dev); | |
490 | + rth->fl.fl4_gw = 0; | |
491 | rth->rt_gateway = daddr; | |
492 | rth->rt_spec_dst= spec_dst; | |
493 | rth->u.dst.input= ip_local_deliver; | |
494 | @@ -1865,8 +1885,9 @@ | |
495 | goto e_inval; | |
496 | } | |
497 | ||
498 | -int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, | |
499 | - u8 tos, struct net_device *dev) | |
500 | +static inline int | |
501 | +ip_route_input_cached(struct sk_buff *skb, u32 daddr, u32 saddr, | |
502 | + u8 tos, struct net_device *dev, u32 lsrc) | |
503 | { | |
504 | struct rtable * rth; | |
505 | unsigned hash; | |
506 | @@ -1881,6 +1902,7 @@ | |
507 | if (rth->fl.fl4_dst == daddr && | |
508 | rth->fl.fl4_src == saddr && | |
509 | rth->fl.iif == iif && | |
510 | + rth->fl.fl4_lsrc == lsrc && | |
511 | rth->fl.oif == 0 && | |
512 | #ifdef CONFIG_IP_ROUTE_FWMARK | |
513 | rth->fl.fl4_fwmark == skb->nfmark && | |
514 | @@ -1929,9 +1951,21 @@ | |
515 | read_unlock(&inetdev_lock); | |
516 | return -EINVAL; | |
517 | } | |
518 | - return ip_route_input_slow(skb, daddr, saddr, tos, dev); | |
519 | + return ip_route_input_slow(skb, daddr, saddr, tos, dev, lsrc); | |
520 | } | |
521 | ||
522 | +int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, | |
523 | + u8 tos, struct net_device *dev) | |
524 | +{ | |
525 | + return ip_route_input_cached(skb, daddr, saddr, tos, dev, 0); | |
526 | +} | |
527 | + | |
528 | +int ip_route_input_lookup(struct sk_buff *skb, u32 daddr, u32 saddr, | |
529 | + u8 tos, struct net_device *dev, u32 lsrc) | |
530 | +{ | |
531 | + return ip_route_input_cached(skb, daddr, saddr, tos, dev, lsrc); | |
532 | +} | |
533 | + | |
534 | /* | |
535 | * Major route resolver routine. | |
536 | */ | |
537 | @@ -1942,6 +1976,7 @@ | |
538 | struct flowi fl = { .nl_u = { .ip4_u = | |
539 | { .daddr = oldflp->fl4_dst, | |
540 | .saddr = oldflp->fl4_src, | |
541 | + .gw = oldflp->fl4_gw, | |
542 | .tos = tos & IPTOS_RT_MASK, | |
543 | .scope = ((tos & RTO_ONLINK) ? | |
544 | RT_SCOPE_LINK : | |
545 | @@ -2045,6 +2080,7 @@ | |
546 | dev_out = &loopback_dev; | |
547 | dev_hold(dev_out); | |
548 | fl.oif = loopback_dev.ifindex; | |
549 | + fl.fl4_gw = 0; | |
550 | res.type = RTN_LOCAL; | |
551 | flags |= RTCF_LOCAL; | |
552 | goto make_route; | |
553 | @@ -2095,6 +2131,7 @@ | |
554 | dev_out = &loopback_dev; | |
555 | dev_hold(dev_out); | |
556 | fl.oif = dev_out->ifindex; | |
557 | + fl.fl4_gw = 0; | |
558 | if (res.fi) | |
559 | fib_info_put(res.fi); | |
560 | res.fi = NULL; | |
561 | @@ -2170,6 +2207,7 @@ | |
562 | rth->fl.fl4_tos = tos; | |
563 | rth->fl.fl4_src = oldflp->fl4_src; | |
564 | rth->fl.oif = oldflp->oif; | |
565 | + rth->fl.fl4_gw = oldflp->fl4_gw; | |
566 | #ifdef CONFIG_IP_ROUTE_FWMARK | |
567 | rth->fl.fl4_fwmark= oldflp->fl4_fwmark; | |
568 | #endif | |
569 | @@ -2249,6 +2287,7 @@ | |
570 | rth->fl.fl4_src == flp->fl4_src && | |
571 | rth->fl.iif == 0 && | |
572 | rth->fl.oif == flp->oif && | |
573 | + rth->fl.fl4_gw == flp->fl4_gw && | |
574 | #ifdef CONFIG_IP_ROUTE_FWMARK | |
575 | rth->fl.fl4_fwmark == flp->fl4_fwmark && | |
576 | #endif | |
577 | @@ -2862,3 +2901,4 @@ | |
578 | EXPORT_SYMBOL(__ip_select_ident); | |
579 | EXPORT_SYMBOL(ip_route_input); | |
580 | EXPORT_SYMBOL(ip_route_output_key); | |
581 | +EXPORT_SYMBOL(ip_route_input_lookup); |