|
@@ -217,17 +217,37 @@ static inline char rt_tos2priority(u8 tos)
|
|
return ip_tos2prio[IPTOS_TOS(tos)>>1];
|
|
return ip_tos2prio[IPTOS_TOS(tos)>>1];
|
|
}
|
|
}
|
|
|
|
|
|
-static inline struct rtable *ip_route_connect(__be32 dst, __be32 src, u32 tos,
|
|
|
|
- int oif, u8 protocol,
|
|
|
|
- __be16 sport, __be16 dport,
|
|
|
|
- struct sock *sk, bool can_sleep)
|
|
|
|
|
|
+/* ip_route_connect() and ip_route_newports() work in tandem whilst
|
|
|
|
+ * binding a socket for a new outgoing connection.
|
|
|
|
+ *
|
|
|
|
+ * In order to use IPSEC properly, we must, in the end, have a
|
|
|
|
+ * route that was looked up using all available keys including source
|
|
|
|
+ * and destination ports.
|
|
|
|
+ *
|
|
|
|
+ * However, if a source port needs to be allocated (the user specified
|
|
|
|
+ * a wildcard source port) we need to obtain addressing information
|
|
|
|
+ * in order to perform that allocation.
|
|
|
|
+ *
|
|
|
|
+ * So ip_route_connect() looks up a route using wildcarded source and
|
|
|
|
+ * destination ports in the key, simply so that we can get a pair of
|
|
|
|
+ * addresses to use for port allocation.
|
|
|
|
+ *
|
|
|
|
+ * Later, once the ports are allocated, ip_route_newports() will make
|
|
|
|
+ * another route lookup if needed to make sure we catch any IPSEC
|
|
|
|
+ * rules keyed on the port information.
|
|
|
|
+ *
|
|
|
|
+ * The callers allocate the flow key on their stack, and must pass in
|
|
|
|
+ * the same flowi4 object to both the ip_route_connect() and the
|
|
|
|
+ * ip_route_newports() calls.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst, __be32 src,
|
|
|
|
+ u32 tos, int oif, u8 protocol,
|
|
|
|
+ __be16 sport, __be16 dport,
|
|
|
|
+ struct sock *sk, bool can_sleep)
|
|
{
|
|
{
|
|
- struct net *net = sock_net(sk);
|
|
|
|
- struct rtable *rt;
|
|
|
|
- struct flowi4 fl4;
|
|
|
|
- __u8 flow_flags;
|
|
|
|
|
|
+ __u8 flow_flags = 0;
|
|
|
|
|
|
- flow_flags = 0;
|
|
|
|
if (inet_sk(sk)->transparent)
|
|
if (inet_sk(sk)->transparent)
|
|
flow_flags |= FLOWI_FLAG_ANYSRC;
|
|
flow_flags |= FLOWI_FLAG_ANYSRC;
|
|
if (protocol == IPPROTO_TCP)
|
|
if (protocol == IPPROTO_TCP)
|
|
@@ -235,41 +255,45 @@ static inline struct rtable *ip_route_connect(__be32 dst, __be32 src, u32 tos,
|
|
if (can_sleep)
|
|
if (can_sleep)
|
|
flow_flags |= FLOWI_FLAG_CAN_SLEEP;
|
|
flow_flags |= FLOWI_FLAG_CAN_SLEEP;
|
|
|
|
|
|
- flowi4_init_output(&fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE,
|
|
|
|
|
|
+ flowi4_init_output(fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE,
|
|
protocol, flow_flags, dst, src, dport, sport);
|
|
protocol, flow_flags, dst, src, dport, sport);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline struct rtable *ip_route_connect(struct flowi4 *fl4,
|
|
|
|
+ __be32 dst, __be32 src, u32 tos,
|
|
|
|
+ int oif, u8 protocol,
|
|
|
|
+ __be16 sport, __be16 dport,
|
|
|
|
+ struct sock *sk, bool can_sleep)
|
|
|
|
+{
|
|
|
|
+ struct net *net = sock_net(sk);
|
|
|
|
+ struct rtable *rt;
|
|
|
|
+
|
|
|
|
+ ip_route_connect_init(fl4, dst, src, tos, oif, protocol,
|
|
|
|
+ sport, dport, sk, can_sleep);
|
|
|
|
|
|
if (!dst || !src) {
|
|
if (!dst || !src) {
|
|
- rt = __ip_route_output_key(net, &fl4);
|
|
|
|
|
|
+ rt = __ip_route_output_key(net, fl4);
|
|
if (IS_ERR(rt))
|
|
if (IS_ERR(rt))
|
|
return rt;
|
|
return rt;
|
|
- fl4.daddr = rt->rt_dst;
|
|
|
|
- fl4.saddr = rt->rt_src;
|
|
|
|
|
|
+ fl4->daddr = rt->rt_dst;
|
|
|
|
+ fl4->saddr = rt->rt_src;
|
|
ip_rt_put(rt);
|
|
ip_rt_put(rt);
|
|
}
|
|
}
|
|
- security_sk_classify_flow(sk, flowi4_to_flowi(&fl4));
|
|
|
|
- return ip_route_output_flow(net, &fl4, sk);
|
|
|
|
|
|
+ security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
|
|
|
|
+ return ip_route_output_flow(net, fl4, sk);
|
|
}
|
|
}
|
|
|
|
|
|
-static inline struct rtable *ip_route_newports(struct rtable *rt,
|
|
|
|
- u8 protocol, __be16 orig_sport,
|
|
|
|
- __be16 orig_dport, __be16 sport,
|
|
|
|
- __be16 dport, struct sock *sk)
|
|
|
|
|
|
+static inline struct rtable *ip_route_newports(struct flowi4 *fl4, struct rtable *rt,
|
|
|
|
+ __be16 orig_sport, __be16 orig_dport,
|
|
|
|
+ __be16 sport, __be16 dport,
|
|
|
|
+ struct sock *sk)
|
|
{
|
|
{
|
|
if (sport != orig_sport || dport != orig_dport) {
|
|
if (sport != orig_sport || dport != orig_dport) {
|
|
- struct flowi4 fl4;
|
|
|
|
- __u8 flow_flags;
|
|
|
|
-
|
|
|
|
- flow_flags = 0;
|
|
|
|
- if (inet_sk(sk)->transparent)
|
|
|
|
- flow_flags |= FLOWI_FLAG_ANYSRC;
|
|
|
|
- if (protocol == IPPROTO_TCP)
|
|
|
|
- flow_flags |= FLOWI_FLAG_PRECOW_METRICS;
|
|
|
|
- flowi4_init_output(&fl4, rt->rt_oif, rt->rt_mark, rt->rt_tos,
|
|
|
|
- RT_SCOPE_UNIVERSE, protocol, flow_flags,
|
|
|
|
- rt->rt_dst, rt->rt_src, dport, sport);
|
|
|
|
|
|
+ fl4->fl4_dport = dport;
|
|
|
|
+ fl4->fl4_sport = sport;
|
|
ip_rt_put(rt);
|
|
ip_rt_put(rt);
|
|
- security_sk_classify_flow(sk, flowi4_to_flowi(&fl4));
|
|
|
|
- return ip_route_output_flow(sock_net(sk), &fl4, sk);
|
|
|
|
|
|
+ security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
|
|
|
|
+ return ip_route_output_flow(sock_net(sk), fl4, sk);
|
|
}
|
|
}
|
|
return rt;
|
|
return rt;
|
|
}
|
|
}
|