aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulian Anastasov <ja@ssi.bg>2012-02-04 08:04:46 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-02-29 19:34:03 -0500
commitdbde1bae2933018c576abcc28daf082fcd17c8d3 (patch)
tree21a7544b504ed90d1dee8bff035ce221d75d7ced
parentab2fd30a38e23f0b6f2e331889b31f4f6fb2378a (diff)
ipv4: reset flowi parameters on route connect
[ Upstream commit e6b45241c57a83197e5de9166b3b0d32ac562609 ] Eric Dumazet found that commit 813b3b5db83 (ipv4: Use caller's on-stack flowi as-is in output route lookups.) that comes in 3.0 added a regression. The problem appears to be that resulting flowi4_oif is used incorrectly as input parameter to some routing lookups. The result is that when connecting to local port without listener if the IP address that is used is not on a loopback interface we incorrectly assign RTN_UNICAST to the output route because no route is matched by oif=lo. The RST packet can not be sent immediately by tcp_v4_send_reset because it expects RTN_LOCAL. So, change ip_route_connect and ip_route_newports to update the flowi4 fields that are input parameters because we do not want unnecessary binding to oif. To make it clear what are the input parameters that can be modified during lookup and to show which fields of floiw4 are reused add a new function to update the flowi4 structure: flowi4_update_output. Thanks to Yurij M. Plotnikov for providing a bug report including a program to reproduce the problem. Thanks to Eric Dumazet for tracking the problem down to tcp_v4_send_reset and providing initial fix. Reported-by: Yurij M. Plotnikov <Yurij.Plotnikov@oktetlabs.ru> Signed-off-by: Julian Anastasov <ja@ssi.bg> Acked-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--include/net/flow.h10
-rw-r--r--include/net/route.h4
2 files changed, 14 insertions, 0 deletions
diff --git a/include/net/flow.h b/include/net/flow.h
index 32359fdc7e7..e37cfda9c0f 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -90,6 +90,16 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif,
90 fl4->fl4_dport = dport; 90 fl4->fl4_dport = dport;
91 fl4->fl4_sport = sport; 91 fl4->fl4_sport = sport;
92} 92}
93
94/* Reset some input parameters after previous lookup */
95static inline void flowi4_update_output(struct flowi4 *fl4, int oif, __u8 tos,
96 __be32 daddr, __be32 saddr)
97{
98 fl4->flowi4_oif = oif;
99 fl4->flowi4_tos = tos;
100 fl4->daddr = daddr;
101 fl4->saddr = saddr;
102}
93 103
94 104
95struct flowi6 { 105struct flowi6 {
diff --git a/include/net/route.h b/include/net/route.h
index db7b3432f07..5d7aae4ab2e 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -270,6 +270,7 @@ static inline struct rtable *ip_route_connect(struct flowi4 *fl4,
270 if (IS_ERR(rt)) 270 if (IS_ERR(rt))
271 return rt; 271 return rt;
272 ip_rt_put(rt); 272 ip_rt_put(rt);
273 flowi4_update_output(fl4, oif, tos, fl4->daddr, fl4->saddr);
273 } 274 }
274 security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); 275 security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
275 return ip_route_output_flow(net, fl4, sk); 276 return ip_route_output_flow(net, fl4, sk);
@@ -284,6 +285,9 @@ static inline struct rtable *ip_route_newports(struct flowi4 *fl4, struct rtable
284 fl4->fl4_dport = dport; 285 fl4->fl4_dport = dport;
285 fl4->fl4_sport = sport; 286 fl4->fl4_sport = sport;
286 ip_rt_put(rt); 287 ip_rt_put(rt);
288 flowi4_update_output(fl4, sk->sk_bound_dev_if,
289 RT_CONN_FLAGS(sk), fl4->daddr,
290 fl4->saddr);
287 security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); 291 security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
288 return ip_route_output_flow(sock_net(sk), fl4, sk); 292 return ip_route_output_flow(sock_net(sk), fl4, sk);
289 } 293 }