diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 6465e7b3e891f61a8fd474f68c5e9a645d40d0ea..99be6801c79570e206e4ef1dcab781b48fa7b323 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1409,7 +1409,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) struct ip_vs_protocol *pp; struct ip_vs_proto_data *pd; unsigned int offset, offset2, ihl, verdict; - bool ipip; + bool ipip, new_cp = false; *related = 1; @@ -1487,8 +1487,17 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) * For IPIP this is error for request, not for reply. */ cp = pp->conn_in_get(AF_INET, skb, &ciph); - if (!cp) - return NF_ACCEPT; + + if (!cp) { + int v; + + if (!sysctl_schedule_icmp(net_ipvs(net))) + return NF_ACCEPT; + + if (!ip_vs_try_to_schedule(AF_INET, skb, pd, &v, &cp, &ciph)) + return v; + new_cp = true; + } verdict = NF_DROP; @@ -1565,7 +1574,10 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) verdict = ip_vs_icmp_xmit(skb, cp, pp, offset, hooknum, &ciph); out: - __ip_vs_conn_put(cp); + if (likely(!new_cp)) + __ip_vs_conn_put(cp); + else + ip_vs_conn_put(cp); return verdict; } @@ -1581,6 +1593,7 @@ static int ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, struct ip_vs_protocol *pp; struct ip_vs_proto_data *pd; unsigned int offset, verdict; + bool new_cp = false; *related = 1; @@ -1631,13 +1644,23 @@ static int ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, */ cp = pp->conn_in_get(AF_INET6, skb, &ciph); - if (!cp) - return NF_ACCEPT; + if (!cp) { + int v; + + if (!sysctl_schedule_icmp(net_ipvs(net))) + return NF_ACCEPT; + + if (!ip_vs_try_to_schedule(AF_INET6, skb, pd, &v, &cp, &ciph)) + return v; + + new_cp = true; + } + /* VS/TUN, VS/DR and LOCALNODE just let it go */ if ((hooknum == NF_INET_LOCAL_OUT) && (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)) { - __ip_vs_conn_put(cp); - return NF_ACCEPT; + verdict = NF_ACCEPT; + goto out; } /* do the statistics and put it back */ @@ -1651,7 +1674,11 @@ static int ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset, hooknum, &ciph); - __ip_vs_conn_put(cp); +out: + if (likely(!new_cp)) + __ip_vs_conn_put(cp); + else + ip_vs_conn_put(cp); return verdict; } diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c index 5b84c0b566424dce498c7ff85ee3b1060df4047f..cd2984f3dad704fe8dd8db95b475bac26a366f49 100644 --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c @@ -19,6 +19,12 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, sctp_chunkhdr_t _schunkh, *sch; sctp_sctphdr_t *sh, _sctph; + if (ip_vs_iph_icmp(iph)) { + /* TEMPORARY - do not schedule icmp yet */ + *verdict = NF_ACCEPT; + return 0; + } + sh = skb_header_pointer(skb, iph->len, sizeof(_sctph), &_sctph); if (sh == NULL) { *verdict = NF_DROP; diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c index 8e92beb0cca9920238421af8a5b5206869c357e0..dbc707514f2999c55c3a046367e3648d2d18ad27 100644 --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c @@ -41,6 +41,12 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, struct tcphdr _tcph, *th; struct netns_ipvs *ipvs; + if (ip_vs_iph_icmp(iph)) { + /* TEMPORARY - do not schedule icmp yet */ + *verdict = NF_ACCEPT; + return 0; + } + th = skb_header_pointer(skb, iph->len, sizeof(_tcph), &_tcph); if (th == NULL) { *verdict = NF_DROP; @@ -48,6 +54,7 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, } net = skb_net(skb); ipvs = net_ipvs(net); + /* No !th->ack check to allow scheduling on SYN+ACK for Active FTP */ rcu_read_lock(); if ((th->syn || sysctl_sloppy_tcp(ipvs)) && !th->rst && diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c index b62a3c0ff9bf400817b20ec1ea4056586ed5d1dc..1403be25098840ae51ef6dcaee5bdd054d004d78 100644 --- a/net/netfilter/ipvs/ip_vs_proto_udp.c +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c @@ -37,6 +37,12 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, struct ip_vs_service *svc; struct udphdr _udph, *uh; + if (ip_vs_iph_icmp(iph)) { + /* TEMPORARY - do not schedule icmp yet */ + *verdict = NF_ACCEPT; + return 0; + } + /* IPv6 fragments, only first fragment will hit this */ uh = skb_header_pointer(skb, iph->len, sizeof(_udph), &_udph); if (uh == NULL) {