Commit 3c5ab3f3 authored by Julian Anastasov's avatar Julian Anastasov Committed by Simon Horman

ipvs: SNAT packet replies only for NATed connections

We do not check if packet from real server is for NAT
connection before performing SNAT. This causes problems
for setups that use DR/TUN and allow local clients to
access the real server directly, for example:

- local client in director creates IPVS-DR/TUN connection
CIP->VIP and the request packets are routed to RIP.
Talks are finished but IPVS connection is not expired yet.

- second local client creates non-IPVS connection CIP->RIP
with same reply tuple RIP->CIP and when replies are received
on LOCAL_IN we wrongly assign them for the first client
connection because RIP->CIP matches the reply direction.
As result, IPVS SNATs replies for non-IPVS connections.

The problem is more visible to local UDP clients but in rare
cases it can happen also for TCP or remote clients when the
real server sends the reply traffic via the director.

So, better to be more precise for the reply traffic.
As replies are not expected for DR/TUN connections, better
to not touch them.
Reported-by: default avatarNick Moriarty <nick.moriarty@york.ac.uk>
Tested-by: default avatarNick Moriarty <nick.moriarty@york.ac.uk>
Signed-off-by: default avatarJulian Anastasov <ja@ssi.bg>
Signed-off-by: default avatarSimon Horman <horms@verge.net.au>
parent f411af68
...@@ -849,10 +849,8 @@ static int handle_response_icmp(int af, struct sk_buff *skb, ...@@ -849,10 +849,8 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
{ {
unsigned int verdict = NF_DROP; unsigned int verdict = NF_DROP;
if (IP_VS_FWD_METHOD(cp) != 0) { if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
pr_err("shouldn't reach here, because the box is on the " goto ignore_cp;
"half connection in the tun/dr module.\n");
}
/* Ensure the checksum is correct */ /* Ensure the checksum is correct */
if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) { if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
...@@ -886,6 +884,8 @@ static int handle_response_icmp(int af, struct sk_buff *skb, ...@@ -886,6 +884,8 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
ip_vs_notrack(skb); ip_vs_notrack(skb);
else else
ip_vs_update_conntrack(skb, cp, 0); ip_vs_update_conntrack(skb, cp, 0);
ignore_cp:
verdict = NF_ACCEPT; verdict = NF_ACCEPT;
out: out:
...@@ -1385,8 +1385,11 @@ ip_vs_out(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, in ...@@ -1385,8 +1385,11 @@ ip_vs_out(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, in
*/ */
cp = pp->conn_out_get(ipvs, af, skb, &iph); cp = pp->conn_out_get(ipvs, af, skb, &iph);
if (likely(cp)) if (likely(cp)) {
if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
goto ignore_cp;
return handle_response(af, skb, pd, cp, &iph, hooknum); return handle_response(af, skb, pd, cp, &iph, hooknum);
}
/* Check for real-server-started requests */ /* Check for real-server-started requests */
if (atomic_read(&ipvs->conn_out_counter)) { if (atomic_read(&ipvs->conn_out_counter)) {
...@@ -1444,9 +1447,15 @@ ip_vs_out(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, in ...@@ -1444,9 +1447,15 @@ ip_vs_out(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, in
} }
} }
} }
out:
IP_VS_DBG_PKT(12, af, pp, skb, iph.off, IP_VS_DBG_PKT(12, af, pp, skb, iph.off,
"ip_vs_out: packet continues traversal as normal"); "ip_vs_out: packet continues traversal as normal");
return NF_ACCEPT; return NF_ACCEPT;
ignore_cp:
__ip_vs_conn_put(cp);
goto out;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment