Skip to content

Commit 8294448

Browse files
Julian Anastasovgregkh
authored andcommitted
ipvs: SNAT packet replies only for NATed connections
commit 3c5ab3f upstream. 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: Nick Moriarty <[email protected]> Tested-by: Nick Moriarty <[email protected]> Signed-off-by: Julian Anastasov <[email protected]> Signed-off-by: Simon Horman <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 48a72b5 commit 8294448

File tree

1 file changed

+14
-5
lines changed

1 file changed

+14
-5
lines changed

net/netfilter/ipvs/ip_vs_core.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -845,10 +845,8 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
845845
{
846846
unsigned int verdict = NF_DROP;
847847

848-
if (IP_VS_FWD_METHOD(cp) != 0) {
849-
pr_err("shouldn't reach here, because the box is on the "
850-
"half connection in the tun/dr module.\n");
851-
}
848+
if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
849+
goto ignore_cp;
852850

853851
/* Ensure the checksum is correct */
854852
if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
@@ -882,6 +880,8 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
882880
ip_vs_notrack(skb);
883881
else
884882
ip_vs_update_conntrack(skb, cp, 0);
883+
884+
ignore_cp:
885885
verdict = NF_ACCEPT;
886886

887887
out:
@@ -1242,8 +1242,11 @@ ip_vs_out(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, in
12421242
*/
12431243
cp = pp->conn_out_get(ipvs, af, skb, &iph);
12441244

1245-
if (likely(cp))
1245+
if (likely(cp)) {
1246+
if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
1247+
goto ignore_cp;
12461248
return handle_response(af, skb, pd, cp, &iph, hooknum);
1249+
}
12471250
if (sysctl_nat_icmp_send(ipvs) &&
12481251
(pp->protocol == IPPROTO_TCP ||
12491252
pp->protocol == IPPROTO_UDP ||
@@ -1285,9 +1288,15 @@ ip_vs_out(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, in
12851288
}
12861289
}
12871290
}
1291+
1292+
out:
12881293
IP_VS_DBG_PKT(12, af, pp, skb, iph.off,
12891294
"ip_vs_out: packet continues traversal as normal");
12901295
return NF_ACCEPT;
1296+
1297+
ignore_cp:
1298+
__ip_vs_conn_put(cp);
1299+
goto out;
12911300
}
12921301

12931302
/*

0 commit comments

Comments
 (0)