 e6b45241c5
			
		
	
	
	e6b45241c5
	
	
	
		
			
			Eric Dumazet found that commit 813b3b5db8
(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>
		
	
			
		
			
				
	
	
		
			226 lines
		
	
	
	
		
			5.7 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			226 lines
		
	
	
	
		
			5.7 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *
 | |
|  *	Generic internet FLOW.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #ifndef _NET_FLOW_H
 | |
| #define _NET_FLOW_H
 | |
| 
 | |
| #include <linux/socket.h>
 | |
| #include <linux/in6.h>
 | |
| #include <linux/atomic.h>
 | |
| 
 | |
| struct flowi_common {
 | |
| 	int	flowic_oif;
 | |
| 	int	flowic_iif;
 | |
| 	__u32	flowic_mark;
 | |
| 	__u8	flowic_tos;
 | |
| 	__u8	flowic_scope;
 | |
| 	__u8	flowic_proto;
 | |
| 	__u8	flowic_flags;
 | |
| #define FLOWI_FLAG_ANYSRC		0x01
 | |
| #define FLOWI_FLAG_PRECOW_METRICS	0x02
 | |
| #define FLOWI_FLAG_CAN_SLEEP		0x04
 | |
| 	__u32	flowic_secid;
 | |
| };
 | |
| 
 | |
| union flowi_uli {
 | |
| 	struct {
 | |
| 		__be16	dport;
 | |
| 		__be16	sport;
 | |
| 	} ports;
 | |
| 
 | |
| 	struct {
 | |
| 		__u8	type;
 | |
| 		__u8	code;
 | |
| 	} icmpt;
 | |
| 
 | |
| 	struct {
 | |
| 		__le16	dport;
 | |
| 		__le16	sport;
 | |
| 	} dnports;
 | |
| 
 | |
| 	__be32		spi;
 | |
| 	__be32		gre_key;
 | |
| 
 | |
| 	struct {
 | |
| 		__u8	type;
 | |
| 	} mht;
 | |
| };
 | |
| 
 | |
| struct flowi4 {
 | |
| 	struct flowi_common	__fl_common;
 | |
| #define flowi4_oif		__fl_common.flowic_oif
 | |
| #define flowi4_iif		__fl_common.flowic_iif
 | |
| #define flowi4_mark		__fl_common.flowic_mark
 | |
| #define flowi4_tos		__fl_common.flowic_tos
 | |
| #define flowi4_scope		__fl_common.flowic_scope
 | |
| #define flowi4_proto		__fl_common.flowic_proto
 | |
| #define flowi4_flags		__fl_common.flowic_flags
 | |
| #define flowi4_secid		__fl_common.flowic_secid
 | |
| 
 | |
| 	/* (saddr,daddr) must be grouped, same order as in IP header */
 | |
| 	__be32			saddr;
 | |
| 	__be32			daddr;
 | |
| 
 | |
| 	union flowi_uli		uli;
 | |
| #define fl4_sport		uli.ports.sport
 | |
| #define fl4_dport		uli.ports.dport
 | |
| #define fl4_icmp_type		uli.icmpt.type
 | |
| #define fl4_icmp_code		uli.icmpt.code
 | |
| #define fl4_ipsec_spi		uli.spi
 | |
| #define fl4_mh_type		uli.mht.type
 | |
| #define fl4_gre_key		uli.gre_key
 | |
| } __attribute__((__aligned__(BITS_PER_LONG/8)));
 | |
| 
 | |
| static inline void flowi4_init_output(struct flowi4 *fl4, int oif,
 | |
| 				      __u32 mark, __u8 tos, __u8 scope,
 | |
| 				      __u8 proto, __u8 flags,
 | |
| 				      __be32 daddr, __be32 saddr,
 | |
| 				      __be16 dport, __be16 sport)
 | |
| {
 | |
| 	fl4->flowi4_oif = oif;
 | |
| 	fl4->flowi4_iif = 0;
 | |
| 	fl4->flowi4_mark = mark;
 | |
| 	fl4->flowi4_tos = tos;
 | |
| 	fl4->flowi4_scope = scope;
 | |
| 	fl4->flowi4_proto = proto;
 | |
| 	fl4->flowi4_flags = flags;
 | |
| 	fl4->flowi4_secid = 0;
 | |
| 	fl4->daddr = daddr;
 | |
| 	fl4->saddr = saddr;
 | |
| 	fl4->fl4_dport = dport;
 | |
| 	fl4->fl4_sport = sport;
 | |
| }
 | |
| 
 | |
| /* Reset some input parameters after previous lookup */
 | |
| static inline void flowi4_update_output(struct flowi4 *fl4, int oif, __u8 tos,
 | |
| 					__be32 daddr, __be32 saddr)
 | |
| {
 | |
| 	fl4->flowi4_oif = oif;
 | |
| 	fl4->flowi4_tos = tos;
 | |
| 	fl4->daddr = daddr;
 | |
| 	fl4->saddr = saddr;
 | |
| }
 | |
| 				      
 | |
| 
 | |
| struct flowi6 {
 | |
| 	struct flowi_common	__fl_common;
 | |
| #define flowi6_oif		__fl_common.flowic_oif
 | |
| #define flowi6_iif		__fl_common.flowic_iif
 | |
| #define flowi6_mark		__fl_common.flowic_mark
 | |
| #define flowi6_tos		__fl_common.flowic_tos
 | |
| #define flowi6_scope		__fl_common.flowic_scope
 | |
| #define flowi6_proto		__fl_common.flowic_proto
 | |
| #define flowi6_flags		__fl_common.flowic_flags
 | |
| #define flowi6_secid		__fl_common.flowic_secid
 | |
| 	struct in6_addr		daddr;
 | |
| 	struct in6_addr		saddr;
 | |
| 	__be32			flowlabel;
 | |
| 	union flowi_uli		uli;
 | |
| #define fl6_sport		uli.ports.sport
 | |
| #define fl6_dport		uli.ports.dport
 | |
| #define fl6_icmp_type		uli.icmpt.type
 | |
| #define fl6_icmp_code		uli.icmpt.code
 | |
| #define fl6_ipsec_spi		uli.spi
 | |
| #define fl6_mh_type		uli.mht.type
 | |
| #define fl6_gre_key		uli.gre_key
 | |
| } __attribute__((__aligned__(BITS_PER_LONG/8)));
 | |
| 
 | |
| struct flowidn {
 | |
| 	struct flowi_common	__fl_common;
 | |
| #define flowidn_oif		__fl_common.flowic_oif
 | |
| #define flowidn_iif		__fl_common.flowic_iif
 | |
| #define flowidn_mark		__fl_common.flowic_mark
 | |
| #define flowidn_scope		__fl_common.flowic_scope
 | |
| #define flowidn_proto		__fl_common.flowic_proto
 | |
| #define flowidn_flags		__fl_common.flowic_flags
 | |
| 	__le16			daddr;
 | |
| 	__le16			saddr;
 | |
| 	union flowi_uli		uli;
 | |
| #define fld_sport		uli.ports.sport
 | |
| #define fld_dport		uli.ports.dport
 | |
| } __attribute__((__aligned__(BITS_PER_LONG/8)));
 | |
| 
 | |
| struct flowi {
 | |
| 	union {
 | |
| 		struct flowi_common	__fl_common;
 | |
| 		struct flowi4		ip4;
 | |
| 		struct flowi6		ip6;
 | |
| 		struct flowidn		dn;
 | |
| 	} u;
 | |
| #define flowi_oif	u.__fl_common.flowic_oif
 | |
| #define flowi_iif	u.__fl_common.flowic_iif
 | |
| #define flowi_mark	u.__fl_common.flowic_mark
 | |
| #define flowi_tos	u.__fl_common.flowic_tos
 | |
| #define flowi_scope	u.__fl_common.flowic_scope
 | |
| #define flowi_proto	u.__fl_common.flowic_proto
 | |
| #define flowi_flags	u.__fl_common.flowic_flags
 | |
| #define flowi_secid	u.__fl_common.flowic_secid
 | |
| } __attribute__((__aligned__(BITS_PER_LONG/8)));
 | |
| 
 | |
| static inline struct flowi *flowi4_to_flowi(struct flowi4 *fl4)
 | |
| {
 | |
| 	return container_of(fl4, struct flowi, u.ip4);
 | |
| }
 | |
| 
 | |
| static inline struct flowi *flowi6_to_flowi(struct flowi6 *fl6)
 | |
| {
 | |
| 	return container_of(fl6, struct flowi, u.ip6);
 | |
| }
 | |
| 
 | |
| static inline struct flowi *flowidn_to_flowi(struct flowidn *fldn)
 | |
| {
 | |
| 	return container_of(fldn, struct flowi, u.dn);
 | |
| }
 | |
| 
 | |
| typedef unsigned long flow_compare_t;
 | |
| 
 | |
| static inline size_t flow_key_size(u16 family)
 | |
| {
 | |
| 	switch (family) {
 | |
| 	case AF_INET:
 | |
| 		BUILD_BUG_ON(sizeof(struct flowi4) % sizeof(flow_compare_t));
 | |
| 		return sizeof(struct flowi4) / sizeof(flow_compare_t);
 | |
| 	case AF_INET6:
 | |
| 		BUILD_BUG_ON(sizeof(struct flowi6) % sizeof(flow_compare_t));
 | |
| 		return sizeof(struct flowi6) / sizeof(flow_compare_t);
 | |
| 	case AF_DECnet:
 | |
| 		BUILD_BUG_ON(sizeof(struct flowidn) % sizeof(flow_compare_t));
 | |
| 		return sizeof(struct flowidn) / sizeof(flow_compare_t);
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| #define FLOW_DIR_IN	0
 | |
| #define FLOW_DIR_OUT	1
 | |
| #define FLOW_DIR_FWD	2
 | |
| 
 | |
| struct net;
 | |
| struct sock;
 | |
| struct flow_cache_ops;
 | |
| 
 | |
| struct flow_cache_object {
 | |
| 	const struct flow_cache_ops *ops;
 | |
| };
 | |
| 
 | |
| struct flow_cache_ops {
 | |
| 	struct flow_cache_object *(*get)(struct flow_cache_object *);
 | |
| 	int (*check)(struct flow_cache_object *);
 | |
| 	void (*delete)(struct flow_cache_object *);
 | |
| };
 | |
| 
 | |
| typedef struct flow_cache_object *(*flow_resolve_t)(
 | |
| 		struct net *net, const struct flowi *key, u16 family,
 | |
| 		u8 dir, struct flow_cache_object *oldobj, void *ctx);
 | |
| 
 | |
| extern struct flow_cache_object *flow_cache_lookup(
 | |
| 		struct net *net, const struct flowi *key, u16 family,
 | |
| 		u8 dir, flow_resolve_t resolver, void *ctx);
 | |
| 
 | |
| extern void flow_cache_flush(void);
 | |
| extern void flow_cache_flush_deferred(void);
 | |
| extern atomic_t flow_cache_genid;
 | |
| 
 | |
| #endif
 |