aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/ipvs/ip_vs_core.c91
1 files changed, 41 insertions, 50 deletions
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 26e3d99bbeea..05797a5ce157 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -654,8 +654,9 @@ void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
654/* Handle relevant response ICMP messages - forward to the right 654/* Handle relevant response ICMP messages - forward to the right
655 * destination host. Used for NAT and local client. 655 * destination host. Used for NAT and local client.
656 */ 656 */
657static int handle_response_icmp(struct sk_buff *skb, struct iphdr *iph, 657static int handle_response_icmp(int af, struct sk_buff *skb,
658 struct iphdr *cih, struct ip_vs_conn *cp, 658 union nf_inet_addr *snet,
659 __u8 protocol, struct ip_vs_conn *cp,
659 struct ip_vs_protocol *pp, 660 struct ip_vs_protocol *pp,
660 unsigned int offset, unsigned int ihl) 661 unsigned int offset, unsigned int ihl)
661{ 662{
@@ -669,18 +670,22 @@ static int handle_response_icmp(struct sk_buff *skb, struct iphdr *iph,
669 /* Ensure the checksum is correct */ 670 /* Ensure the checksum is correct */
670 if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) { 671 if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
671 /* Failed checksum! */ 672 /* Failed checksum! */
672 IP_VS_DBG(1, 673 IP_VS_DBG_BUF(1, "Forward ICMP: failed checksum from %s!\n",
673 "Forward ICMP: failed checksum from %d.%d.%d.%d!\n", 674 IP_VS_DBG_ADDR(af, snet));
674 NIPQUAD(iph->saddr));
675 goto out; 675 goto out;
676 } 676 }
677 677
678 if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol) 678 if (IPPROTO_TCP == protocol || IPPROTO_UDP == protocol)
679 offset += 2 * sizeof(__u16); 679 offset += 2 * sizeof(__u16);
680 if (!skb_make_writable(skb, offset)) 680 if (!skb_make_writable(skb, offset))
681 goto out; 681 goto out;
682 682
683 ip_vs_nat_icmp(skb, pp, cp, 1); 683#ifdef CONFIG_IP_VS_IPV6
684 if (af == AF_INET6)
685 ip_vs_nat_icmp_v6(skb, pp, cp, 1);
686 else
687#endif
688 ip_vs_nat_icmp(skb, pp, cp, 1);
684 689
685 /* do the statistics and put it back */ 690 /* do the statistics and put it back */
686 ip_vs_out_stats(cp, skb); 691 ip_vs_out_stats(cp, skb);
@@ -708,6 +713,7 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
708 struct ip_vs_conn *cp; 713 struct ip_vs_conn *cp;
709 struct ip_vs_protocol *pp; 714 struct ip_vs_protocol *pp;
710 unsigned int offset, ihl; 715 unsigned int offset, ihl;
716 union nf_inet_addr snet;
711 717
712 *related = 1; 718 *related = 1;
713 719
@@ -766,7 +772,9 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
766 if (!cp) 772 if (!cp)
767 return NF_ACCEPT; 773 return NF_ACCEPT;
768 774
769 return handle_response_icmp(skb, iph, cih, cp, pp, offset, ihl); 775 snet.ip = iph->saddr;
776 return handle_response_icmp(AF_INET, skb, &snet, cih->protocol, cp,
777 pp, offset, ihl);
770} 778}
771 779
772#ifdef CONFIG_IP_VS_IPV6 780#ifdef CONFIG_IP_VS_IPV6
@@ -779,7 +787,8 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related)
779 struct ip_vs_iphdr ciph; 787 struct ip_vs_iphdr ciph;
780 struct ip_vs_conn *cp; 788 struct ip_vs_conn *cp;
781 struct ip_vs_protocol *pp; 789 struct ip_vs_protocol *pp;
782 unsigned int offset, verdict; 790 unsigned int offset;
791 union nf_inet_addr snet;
783 792
784 *related = 1; 793 *related = 1;
785 794
@@ -838,40 +847,9 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related)
838 if (!cp) 847 if (!cp)
839 return NF_ACCEPT; 848 return NF_ACCEPT;
840 849
841 verdict = NF_DROP; 850 snet.in6 = iph->saddr;
842 851 return handle_response_icmp(AF_INET6, skb, &snet, cih->nexthdr, cp,
843 if (IP_VS_FWD_METHOD(cp) != 0) { 852 pp, offset, sizeof(struct ipv6hdr));
844 IP_VS_ERR("shouldn't reach here, because the box is on the "
845 "half connection in the tun/dr module.\n");
846 }
847
848 /* Ensure the checksum is correct */
849 if (!skb_csum_unnecessary(skb)
850 && ip_vs_checksum_complete(skb, sizeof(struct ipv6hdr))) {
851 /* Failed checksum! */
852 IP_VS_DBG(1, "Forward ICMPv6: failed checksum from "
853 NIP6_FMT "!\n",
854 NIP6(iph->saddr));
855 goto out;
856 }
857
858 if (IPPROTO_TCP == cih->nexthdr || IPPROTO_UDP == cih->nexthdr)
859 offset += 2 * sizeof(__u16);
860 if (!skb_make_writable(skb, offset))
861 goto out;
862
863 ip_vs_nat_icmp_v6(skb, pp, cp, 1);
864
865 /* do the statistics and put it back */
866 ip_vs_out_stats(cp, skb);
867
868 skb->ipvs_property = 1;
869 verdict = NF_ACCEPT;
870
871out:
872 __ip_vs_conn_put(cp);
873
874 return verdict;
875} 853}
876#endif 854#endif
877 855
@@ -1055,7 +1033,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
1055 ICMP_DEST_UNREACH, 1033 ICMP_DEST_UNREACH,
1056 ICMP_PORT_UNREACH, 0); 1034 ICMP_PORT_UNREACH, 0);
1057 return NF_DROP; 1035 return NF_DROP;
1058 } 1036 }
1059 } 1037 }
1060 } 1038 }
1061 IP_VS_DBG_PKT(12, pp, skb, 0, 1039 IP_VS_DBG_PKT(12, pp, skb, 0,
@@ -1083,6 +1061,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
1083 struct ip_vs_conn *cp; 1061 struct ip_vs_conn *cp;
1084 struct ip_vs_protocol *pp; 1062 struct ip_vs_protocol *pp;
1085 unsigned int offset, ihl, verdict; 1063 unsigned int offset, ihl, verdict;
1064 union nf_inet_addr snet;
1086 1065
1087 *related = 1; 1066 *related = 1;
1088 1067
@@ -1142,9 +1121,12 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
1142 if (!cp) { 1121 if (!cp) {
1143 /* The packet could also belong to a local client */ 1122 /* The packet could also belong to a local client */
1144 cp = pp->conn_out_get(AF_INET, skb, pp, &ciph, offset, 1); 1123 cp = pp->conn_out_get(AF_INET, skb, pp, &ciph, offset, 1);
1145 if (cp) 1124 if (cp) {
1146 return handle_response_icmp(skb, iph, cih, cp, pp, 1125 snet.ip = iph->saddr;
1126 return handle_response_icmp(AF_INET, skb, &snet,
1127 cih->protocol, cp, pp,
1147 offset, ihl); 1128 offset, ihl);
1129 }
1148 return NF_ACCEPT; 1130 return NF_ACCEPT;
1149 } 1131 }
1150 1132
@@ -1183,6 +1165,7 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)
1183 struct ip_vs_conn *cp; 1165 struct ip_vs_conn *cp;
1184 struct ip_vs_protocol *pp; 1166 struct ip_vs_protocol *pp;
1185 unsigned int offset, verdict; 1167 unsigned int offset, verdict;
1168 union nf_inet_addr snet;
1186 1169
1187 *related = 1; 1170 *related = 1;
1188 1171
@@ -1240,8 +1223,18 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)
1240 ip_vs_fill_iphdr(AF_INET6, cih, &ciph); 1223 ip_vs_fill_iphdr(AF_INET6, cih, &ciph);
1241 /* The embedded headers contain source and dest in reverse order */ 1224 /* The embedded headers contain source and dest in reverse order */
1242 cp = pp->conn_in_get(AF_INET6, skb, pp, &ciph, offset, 1); 1225 cp = pp->conn_in_get(AF_INET6, skb, pp, &ciph, offset, 1);
1243 if (!cp) 1226 if (!cp) {
1227 /* The packet could also belong to a local client */
1228 cp = pp->conn_out_get(AF_INET6, skb, pp, &ciph, offset, 1);
1229 if (cp) {
1230 snet.in6 = iph->saddr;
1231 return handle_response_icmp(AF_INET6, skb, &snet,
1232 cih->nexthdr,
1233 cp, pp, offset,
1234 sizeof(struct ipv6hdr));
1235 }
1244 return NF_ACCEPT; 1236 return NF_ACCEPT;
1237 }
1245 1238
1246 verdict = NF_DROP; 1239 verdict = NF_DROP;
1247 1240
@@ -1281,9 +1274,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
1281 * Big tappo: only PACKET_HOST, including loopback for local client 1274 * Big tappo: only PACKET_HOST, including loopback for local client
1282 * Don't handle local packets on IPv6 for now 1275 * Don't handle local packets on IPv6 for now
1283 */ 1276 */
1284 if (unlikely(skb->pkt_type != PACKET_HOST || 1277 if (unlikely(skb->pkt_type != PACKET_HOST)) {
1285 (af == AF_INET6 || (skb->dev->flags & IFF_LOOPBACK ||
1286 skb->sk)))) {
1287 IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n", 1278 IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n",
1288 skb->pkt_type, 1279 skb->pkt_type,
1289 iph.protocol, 1280 iph.protocol,