diff options
author | Julian Anastasov <ja@ssi.bg> | 2011-05-10 08:46:05 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-05-12 18:24:46 -0400 |
commit | c92f5ca2e5120796c56455e0a4b7cc0dfd6ceb49 (patch) | |
tree | 97048375d75069d308a5ae47b137ba30ff2edd8d | |
parent | 44e3125ccd521585e73e6dd228b283ab26993c68 (diff) |
ipvs: Remove all remaining references to rt->rt_{src,dst}
Remove all remaining references to rt->rt_{src,dst}
by using dest->dst_saddr to cache saddr (used for TUN mode).
For ICMP in FORWARD hook just restrict the rt_mode for NAT
to disable LOCALNODE. All other modes do not allow
IP_VS_RT_MODE_RDR, so we should be safe with the ICMP
forwarding. Using cp->daddr as replacement for rt_dst
is safe for all modes except BYPASS, even when cp->dest is
NULL because it is cp->daddr that is used to assign cp->dest
for sync-ed connections.
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/ip_vs.h | 9 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_core.c | 24 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_xmit.c | 72 |
3 files changed, 54 insertions, 51 deletions
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 9d1f510ab6d0..4fff432aeade 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h | |||
@@ -665,9 +665,7 @@ struct ip_vs_dest { | |||
665 | struct dst_entry *dst_cache; /* destination cache entry */ | 665 | struct dst_entry *dst_cache; /* destination cache entry */ |
666 | u32 dst_rtos; /* RT_TOS(tos) for dst */ | 666 | u32 dst_rtos; /* RT_TOS(tos) for dst */ |
667 | u32 dst_cookie; | 667 | u32 dst_cookie; |
668 | #ifdef CONFIG_IP_VS_IPV6 | 668 | union nf_inet_addr dst_saddr; |
669 | struct in6_addr dst_saddr; | ||
670 | #endif | ||
671 | 669 | ||
672 | /* for virtual service */ | 670 | /* for virtual service */ |
673 | struct ip_vs_service *svc; /* service it belongs to */ | 671 | struct ip_vs_service *svc; /* service it belongs to */ |
@@ -1253,7 +1251,8 @@ extern int ip_vs_tunnel_xmit | |||
1253 | extern int ip_vs_dr_xmit | 1251 | extern int ip_vs_dr_xmit |
1254 | (struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp); | 1252 | (struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp); |
1255 | extern int ip_vs_icmp_xmit | 1253 | extern int ip_vs_icmp_xmit |
1256 | (struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset); | 1254 | (struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, |
1255 | int offset, unsigned int hooknum); | ||
1257 | extern void ip_vs_dst_reset(struct ip_vs_dest *dest); | 1256 | extern void ip_vs_dst_reset(struct ip_vs_dest *dest); |
1258 | 1257 | ||
1259 | #ifdef CONFIG_IP_VS_IPV6 | 1258 | #ifdef CONFIG_IP_VS_IPV6 |
@@ -1267,7 +1266,7 @@ extern int ip_vs_dr_xmit_v6 | |||
1267 | (struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp); | 1266 | (struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp); |
1268 | extern int ip_vs_icmp_xmit_v6 | 1267 | extern int ip_vs_icmp_xmit_v6 |
1269 | (struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, | 1268 | (struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, |
1270 | int offset); | 1269 | int offset, unsigned int hooknum); |
1271 | #endif | 1270 | #endif |
1272 | 1271 | ||
1273 | #ifdef CONFIG_SYSCTL | 1272 | #ifdef CONFIG_SYSCTL |
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index a74dae6c5dbc..bfa808f4da13 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c | |||
@@ -1382,15 +1382,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
1382 | ip_vs_in_stats(cp, skb); | 1382 | ip_vs_in_stats(cp, skb); |
1383 | if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol) | 1383 | if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol) |
1384 | offset += 2 * sizeof(__u16); | 1384 | offset += 2 * sizeof(__u16); |
1385 | verdict = ip_vs_icmp_xmit(skb, cp, pp, offset); | 1385 | verdict = ip_vs_icmp_xmit(skb, cp, pp, offset, hooknum); |
1386 | /* LOCALNODE from FORWARD hook is not supported */ | ||
1387 | if (verdict == NF_ACCEPT && hooknum == NF_INET_FORWARD && | ||
1388 | skb_rtable(skb)->rt_flags & RTCF_LOCAL) { | ||
1389 | IP_VS_DBG(1, "%s(): " | ||
1390 | "local delivery to %pI4 but in FORWARD\n", | ||
1391 | __func__, &skb_rtable(skb)->rt_dst); | ||
1392 | verdict = NF_DROP; | ||
1393 | } | ||
1394 | 1386 | ||
1395 | out: | 1387 | out: |
1396 | __ip_vs_conn_put(cp); | 1388 | __ip_vs_conn_put(cp); |
@@ -1412,7 +1404,6 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
1412 | struct ip_vs_protocol *pp; | 1404 | struct ip_vs_protocol *pp; |
1413 | struct ip_vs_proto_data *pd; | 1405 | struct ip_vs_proto_data *pd; |
1414 | unsigned int offset, verdict; | 1406 | unsigned int offset, verdict; |
1415 | struct rt6_info *rt; | ||
1416 | 1407 | ||
1417 | *related = 1; | 1408 | *related = 1; |
1418 | 1409 | ||
@@ -1474,23 +1465,12 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
1474 | if (!cp) | 1465 | if (!cp) |
1475 | return NF_ACCEPT; | 1466 | return NF_ACCEPT; |
1476 | 1467 | ||
1477 | verdict = NF_DROP; | ||
1478 | |||
1479 | /* do the statistics and put it back */ | 1468 | /* do the statistics and put it back */ |
1480 | ip_vs_in_stats(cp, skb); | 1469 | ip_vs_in_stats(cp, skb); |
1481 | if (IPPROTO_TCP == cih->nexthdr || IPPROTO_UDP == cih->nexthdr || | 1470 | if (IPPROTO_TCP == cih->nexthdr || IPPROTO_UDP == cih->nexthdr || |
1482 | IPPROTO_SCTP == cih->nexthdr) | 1471 | IPPROTO_SCTP == cih->nexthdr) |
1483 | offset += 2 * sizeof(__u16); | 1472 | offset += 2 * sizeof(__u16); |
1484 | verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset); | 1473 | verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset, hooknum); |
1485 | /* LOCALNODE from FORWARD hook is not supported */ | ||
1486 | if (verdict == NF_ACCEPT && hooknum == NF_INET_FORWARD && | ||
1487 | (rt = (struct rt6_info *) skb_dst(skb)) && | ||
1488 | rt->rt6i_dev && rt->rt6i_dev->flags & IFF_LOOPBACK) { | ||
1489 | IP_VS_DBG(1, "%s(): " | ||
1490 | "local delivery to %pI6 but in FORWARD\n", | ||
1491 | __func__, &rt->rt6i_dst); | ||
1492 | verdict = NF_DROP; | ||
1493 | } | ||
1494 | 1474 | ||
1495 | __ip_vs_conn_put(cp); | 1475 | __ip_vs_conn_put(cp); |
1496 | 1476 | ||
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 3f3e0f4c38a5..ee319a4338b0 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c | |||
@@ -87,7 +87,7 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos) | |||
87 | /* Get route to destination or remote server */ | 87 | /* Get route to destination or remote server */ |
88 | static struct rtable * | 88 | static struct rtable * |
89 | __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, | 89 | __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, |
90 | __be32 daddr, u32 rtos, int rt_mode) | 90 | __be32 daddr, u32 rtos, int rt_mode, __be32 *ret_saddr) |
91 | { | 91 | { |
92 | struct net *net = dev_net(skb_dst(skb)->dev); | 92 | struct net *net = dev_net(skb_dst(skb)->dev); |
93 | struct rtable *rt; /* Route to the other host */ | 93 | struct rtable *rt; /* Route to the other host */ |
@@ -98,7 +98,12 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
98 | spin_lock(&dest->dst_lock); | 98 | spin_lock(&dest->dst_lock); |
99 | if (!(rt = (struct rtable *) | 99 | if (!(rt = (struct rtable *) |
100 | __ip_vs_dst_check(dest, rtos))) { | 100 | __ip_vs_dst_check(dest, rtos))) { |
101 | rt = ip_route_output(net, dest->addr.ip, 0, rtos, 0); | 101 | struct flowi4 fl4; |
102 | |||
103 | memset(&fl4, 0, sizeof(fl4)); | ||
104 | fl4.daddr = dest->addr.ip; | ||
105 | fl4.flowi4_tos = rtos; | ||
106 | rt = ip_route_output_key(net, &fl4); | ||
102 | if (IS_ERR(rt)) { | 107 | if (IS_ERR(rt)) { |
103 | spin_unlock(&dest->dst_lock); | 108 | spin_unlock(&dest->dst_lock); |
104 | IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", | 109 | IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", |
@@ -106,19 +111,30 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
106 | return NULL; | 111 | return NULL; |
107 | } | 112 | } |
108 | __ip_vs_dst_set(dest, rtos, dst_clone(&rt->dst), 0); | 113 | __ip_vs_dst_set(dest, rtos, dst_clone(&rt->dst), 0); |
109 | IP_VS_DBG(10, "new dst %pI4, refcnt=%d, rtos=%X\n", | 114 | dest->dst_saddr.ip = fl4.saddr; |
110 | &dest->addr.ip, | 115 | IP_VS_DBG(10, "new dst %pI4, src %pI4, refcnt=%d, " |
116 | "rtos=%X\n", | ||
117 | &dest->addr.ip, &dest->dst_saddr.ip, | ||
111 | atomic_read(&rt->dst.__refcnt), rtos); | 118 | atomic_read(&rt->dst.__refcnt), rtos); |
112 | } | 119 | } |
113 | daddr = dest->addr.ip; | 120 | daddr = dest->addr.ip; |
121 | if (ret_saddr) | ||
122 | *ret_saddr = dest->dst_saddr.ip; | ||
114 | spin_unlock(&dest->dst_lock); | 123 | spin_unlock(&dest->dst_lock); |
115 | } else { | 124 | } else { |
116 | rt = ip_route_output(net, daddr, 0, rtos, 0); | 125 | struct flowi4 fl4; |
126 | |||
127 | memset(&fl4, 0, sizeof(fl4)); | ||
128 | fl4.daddr = daddr; | ||
129 | fl4.flowi4_tos = rtos; | ||
130 | rt = ip_route_output_key(net, &fl4); | ||
117 | if (IS_ERR(rt)) { | 131 | if (IS_ERR(rt)) { |
118 | IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", | 132 | IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", |
119 | &daddr); | 133 | &daddr); |
120 | return NULL; | 134 | return NULL; |
121 | } | 135 | } |
136 | if (ret_saddr) | ||
137 | *ret_saddr = fl4.saddr; | ||
122 | } | 138 | } |
123 | 139 | ||
124 | local = rt->rt_flags & RTCF_LOCAL; | 140 | local = rt->rt_flags & RTCF_LOCAL; |
@@ -249,7 +265,7 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
249 | u32 cookie; | 265 | u32 cookie; |
250 | 266 | ||
251 | dst = __ip_vs_route_output_v6(net, &dest->addr.in6, | 267 | dst = __ip_vs_route_output_v6(net, &dest->addr.in6, |
252 | &dest->dst_saddr, | 268 | &dest->dst_saddr.in6, |
253 | do_xfrm); | 269 | do_xfrm); |
254 | if (!dst) { | 270 | if (!dst) { |
255 | spin_unlock(&dest->dst_lock); | 271 | spin_unlock(&dest->dst_lock); |
@@ -259,11 +275,11 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
259 | cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; | 275 | cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; |
260 | __ip_vs_dst_set(dest, 0, dst_clone(&rt->dst), cookie); | 276 | __ip_vs_dst_set(dest, 0, dst_clone(&rt->dst), cookie); |
261 | IP_VS_DBG(10, "new dst %pI6, src %pI6, refcnt=%d\n", | 277 | IP_VS_DBG(10, "new dst %pI6, src %pI6, refcnt=%d\n", |
262 | &dest->addr.in6, &dest->dst_saddr, | 278 | &dest->addr.in6, &dest->dst_saddr.in6, |
263 | atomic_read(&rt->dst.__refcnt)); | 279 | atomic_read(&rt->dst.__refcnt)); |
264 | } | 280 | } |
265 | if (ret_saddr) | 281 | if (ret_saddr) |
266 | ipv6_addr_copy(ret_saddr, &dest->dst_saddr); | 282 | ipv6_addr_copy(ret_saddr, &dest->dst_saddr.in6); |
267 | spin_unlock(&dest->dst_lock); | 283 | spin_unlock(&dest->dst_lock); |
268 | } else { | 284 | } else { |
269 | dst = __ip_vs_route_output_v6(net, daddr, ret_saddr, do_xfrm); | 285 | dst = __ip_vs_route_output_v6(net, daddr, ret_saddr, do_xfrm); |
@@ -386,7 +402,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
386 | EnterFunction(10); | 402 | EnterFunction(10); |
387 | 403 | ||
388 | if (!(rt = __ip_vs_get_out_rt(skb, NULL, iph->daddr, RT_TOS(iph->tos), | 404 | if (!(rt = __ip_vs_get_out_rt(skb, NULL, iph->daddr, RT_TOS(iph->tos), |
389 | IP_VS_RT_MODE_NON_LOCAL))) | 405 | IP_VS_RT_MODE_NON_LOCAL, NULL))) |
390 | goto tx_error_icmp; | 406 | goto tx_error_icmp; |
391 | 407 | ||
392 | /* MTU checking */ | 408 | /* MTU checking */ |
@@ -518,7 +534,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
518 | RT_TOS(iph->tos), | 534 | RT_TOS(iph->tos), |
519 | IP_VS_RT_MODE_LOCAL | | 535 | IP_VS_RT_MODE_LOCAL | |
520 | IP_VS_RT_MODE_NON_LOCAL | | 536 | IP_VS_RT_MODE_NON_LOCAL | |
521 | IP_VS_RT_MODE_RDR))) | 537 | IP_VS_RT_MODE_RDR, NULL))) |
522 | goto tx_error_icmp; | 538 | goto tx_error_icmp; |
523 | local = rt->rt_flags & RTCF_LOCAL; | 539 | local = rt->rt_flags & RTCF_LOCAL; |
524 | /* | 540 | /* |
@@ -540,7 +556,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
540 | #endif | 556 | #endif |
541 | 557 | ||
542 | /* From world but DNAT to loopback address? */ | 558 | /* From world but DNAT to loopback address? */ |
543 | if (local && ipv4_is_loopback(rt->rt_dst) && | 559 | if (local && ipv4_is_loopback(cp->daddr.ip) && |
544 | rt_is_input_route(skb_rtable(skb))) { | 560 | rt_is_input_route(skb_rtable(skb))) { |
545 | IP_VS_DBG_RL_PKT(1, AF_INET, pp, skb, 0, "ip_vs_nat_xmit(): " | 561 | IP_VS_DBG_RL_PKT(1, AF_INET, pp, skb, 0, "ip_vs_nat_xmit(): " |
546 | "stopping DNAT to loopback address"); | 562 | "stopping DNAT to loopback address"); |
@@ -751,6 +767,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
751 | struct ip_vs_protocol *pp) | 767 | struct ip_vs_protocol *pp) |
752 | { | 768 | { |
753 | struct rtable *rt; /* Route to the other host */ | 769 | struct rtable *rt; /* Route to the other host */ |
770 | __be32 saddr; /* Source for tunnel */ | ||
754 | struct net_device *tdev; /* Device to other host */ | 771 | struct net_device *tdev; /* Device to other host */ |
755 | struct iphdr *old_iph = ip_hdr(skb); | 772 | struct iphdr *old_iph = ip_hdr(skb); |
756 | u8 tos = old_iph->tos; | 773 | u8 tos = old_iph->tos; |
@@ -764,7 +781,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
764 | 781 | ||
765 | if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, | 782 | if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, |
766 | RT_TOS(tos), IP_VS_RT_MODE_LOCAL | | 783 | RT_TOS(tos), IP_VS_RT_MODE_LOCAL | |
767 | IP_VS_RT_MODE_NON_LOCAL))) | 784 | IP_VS_RT_MODE_NON_LOCAL, |
785 | &saddr))) | ||
768 | goto tx_error_icmp; | 786 | goto tx_error_icmp; |
769 | if (rt->rt_flags & RTCF_LOCAL) { | 787 | if (rt->rt_flags & RTCF_LOCAL) { |
770 | ip_rt_put(rt); | 788 | ip_rt_put(rt); |
@@ -832,8 +850,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
832 | iph->frag_off = df; | 850 | iph->frag_off = df; |
833 | iph->protocol = IPPROTO_IPIP; | 851 | iph->protocol = IPPROTO_IPIP; |
834 | iph->tos = tos; | 852 | iph->tos = tos; |
835 | iph->daddr = rt->rt_dst; | 853 | iph->daddr = cp->daddr.ip; |
836 | iph->saddr = rt->rt_src; | 854 | iph->saddr = saddr; |
837 | iph->ttl = old_iph->ttl; | 855 | iph->ttl = old_iph->ttl; |
838 | ip_select_ident(iph, &rt->dst, NULL); | 856 | ip_select_ident(iph, &rt->dst, NULL); |
839 | 857 | ||
@@ -996,7 +1014,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
996 | if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, | 1014 | if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, |
997 | RT_TOS(iph->tos), | 1015 | RT_TOS(iph->tos), |
998 | IP_VS_RT_MODE_LOCAL | | 1016 | IP_VS_RT_MODE_LOCAL | |
999 | IP_VS_RT_MODE_NON_LOCAL))) | 1017 | IP_VS_RT_MODE_NON_LOCAL, NULL))) |
1000 | goto tx_error_icmp; | 1018 | goto tx_error_icmp; |
1001 | if (rt->rt_flags & RTCF_LOCAL) { | 1019 | if (rt->rt_flags & RTCF_LOCAL) { |
1002 | ip_rt_put(rt); | 1020 | ip_rt_put(rt); |
@@ -1114,12 +1132,13 @@ tx_error: | |||
1114 | */ | 1132 | */ |
1115 | int | 1133 | int |
1116 | ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | 1134 | ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, |
1117 | struct ip_vs_protocol *pp, int offset) | 1135 | struct ip_vs_protocol *pp, int offset, unsigned int hooknum) |
1118 | { | 1136 | { |
1119 | struct rtable *rt; /* Route to the other host */ | 1137 | struct rtable *rt; /* Route to the other host */ |
1120 | int mtu; | 1138 | int mtu; |
1121 | int rc; | 1139 | int rc; |
1122 | int local; | 1140 | int local; |
1141 | int rt_mode; | ||
1123 | 1142 | ||
1124 | EnterFunction(10); | 1143 | EnterFunction(10); |
1125 | 1144 | ||
@@ -1140,11 +1159,13 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1140 | * mangle and send the packet here (only for VS/NAT) | 1159 | * mangle and send the packet here (only for VS/NAT) |
1141 | */ | 1160 | */ |
1142 | 1161 | ||
1162 | /* LOCALNODE from FORWARD hook is not supported */ | ||
1163 | rt_mode = (hooknum != NF_INET_FORWARD) ? | ||
1164 | IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | | ||
1165 | IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL; | ||
1143 | if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, | 1166 | if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, |
1144 | RT_TOS(ip_hdr(skb)->tos), | 1167 | RT_TOS(ip_hdr(skb)->tos), |
1145 | IP_VS_RT_MODE_LOCAL | | 1168 | rt_mode, NULL))) |
1146 | IP_VS_RT_MODE_NON_LOCAL | | ||
1147 | IP_VS_RT_MODE_RDR))) | ||
1148 | goto tx_error_icmp; | 1169 | goto tx_error_icmp; |
1149 | local = rt->rt_flags & RTCF_LOCAL; | 1170 | local = rt->rt_flags & RTCF_LOCAL; |
1150 | 1171 | ||
@@ -1167,7 +1188,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1167 | #endif | 1188 | #endif |
1168 | 1189 | ||
1169 | /* From world but DNAT to loopback address? */ | 1190 | /* From world but DNAT to loopback address? */ |
1170 | if (local && ipv4_is_loopback(rt->rt_dst) && | 1191 | if (local && ipv4_is_loopback(cp->daddr.ip) && |
1171 | rt_is_input_route(skb_rtable(skb))) { | 1192 | rt_is_input_route(skb_rtable(skb))) { |
1172 | IP_VS_DBG(1, "%s(): " | 1193 | IP_VS_DBG(1, "%s(): " |
1173 | "stopping DNAT to loopback %pI4\n", | 1194 | "stopping DNAT to loopback %pI4\n", |
@@ -1232,12 +1253,13 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1232 | #ifdef CONFIG_IP_VS_IPV6 | 1253 | #ifdef CONFIG_IP_VS_IPV6 |
1233 | int | 1254 | int |
1234 | ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | 1255 | ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, |
1235 | struct ip_vs_protocol *pp, int offset) | 1256 | struct ip_vs_protocol *pp, int offset, unsigned int hooknum) |
1236 | { | 1257 | { |
1237 | struct rt6_info *rt; /* Route to the other host */ | 1258 | struct rt6_info *rt; /* Route to the other host */ |
1238 | int mtu; | 1259 | int mtu; |
1239 | int rc; | 1260 | int rc; |
1240 | int local; | 1261 | int local; |
1262 | int rt_mode; | ||
1241 | 1263 | ||
1242 | EnterFunction(10); | 1264 | EnterFunction(10); |
1243 | 1265 | ||
@@ -1258,10 +1280,12 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1258 | * mangle and send the packet here (only for VS/NAT) | 1280 | * mangle and send the packet here (only for VS/NAT) |
1259 | */ | 1281 | */ |
1260 | 1282 | ||
1283 | /* LOCALNODE from FORWARD hook is not supported */ | ||
1284 | rt_mode = (hooknum != NF_INET_FORWARD) ? | ||
1285 | IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | | ||
1286 | IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL; | ||
1261 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, | 1287 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, |
1262 | 0, (IP_VS_RT_MODE_LOCAL | | 1288 | 0, rt_mode))) |
1263 | IP_VS_RT_MODE_NON_LOCAL | | ||
1264 | IP_VS_RT_MODE_RDR)))) | ||
1265 | goto tx_error_icmp; | 1289 | goto tx_error_icmp; |
1266 | 1290 | ||
1267 | local = __ip_vs_is_local_route6(rt); | 1291 | local = __ip_vs_is_local_route6(rt); |