diff options
-rw-r--r-- | net/ipv4/ipvs/ip_vs_core.c | 91 |
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 | */ |
657 | static int handle_response_icmp(struct sk_buff *skb, struct iphdr *iph, | 657 | static 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 | |||
871 | out: | ||
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, |