diff options
author | Julian Anastasov <ja@ssi.bg> | 2010-10-17 09:40:51 -0400 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2010-10-21 05:04:01 -0400 |
commit | cb59155f21d4c0507d2034c2953f6a3f7806913d (patch) | |
tree | 33e07206b82254ee272cdcf7184467993ecbe8c7 /net | |
parent | fc604767613b6d2036cdc35b660bc39451040a47 (diff) |
ipvs: changes for local client
This patch deals with local client processing.
Prefer LOCAL_OUT hook for scheduling connections from
local clients. LOCAL_IN is still supported if the packets are
not marked as processed in LOCAL_OUT. The idea to process
requests in LOCAL_OUT is to alter conntrack reply before
it is confirmed at POST_ROUTING. If the local requests are
processed in LOCAL_IN the conntrack can not be updated
and matching by state is impossible.
Add the following handlers:
- ip_vs_reply[46] at LOCAL_IN:99 to process replies from
remote real servers to local clients. Now when both
replies from remote real servers (ip_vs_reply*) and
local real servers (ip_vs_local_reply*) are handled
it is safe to remove the conn_out_get call from ip_vs_in
because it does not support related ICMP packets.
- ip_vs_local_request[46] at LOCAL_OUT:-98 to process
requests from local client
Handling in LOCAL_OUT causes some changes:
- as skb->dev, skb->protocol and skb->pkt_type are not defined
in LOCAL_OUT make sure we set skb->dev before calling icmpv6_send,
prefer skb_dst(skb) for struct net and remove the skb->protocol
checks from TUN transmitters.
[ horms@verge.net.au: removed trailing whitespace ]
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/ipvs/ip_vs_core.c | 266 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_xmit.c | 51 |
2 files changed, 225 insertions, 92 deletions
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index a6c8aff1b47e..5fbcf67af8ec 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c | |||
@@ -529,9 +529,14 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, | |||
529 | * ICMP_PORT_UNREACH is sent here no matter it is TCP/UDP. --WZ | 529 | * ICMP_PORT_UNREACH is sent here no matter it is TCP/UDP. --WZ |
530 | */ | 530 | */ |
531 | #ifdef CONFIG_IP_VS_IPV6 | 531 | #ifdef CONFIG_IP_VS_IPV6 |
532 | if (svc->af == AF_INET6) | 532 | if (svc->af == AF_INET6) { |
533 | if (!skb->dev) { | ||
534 | struct net *net = dev_net(skb_dst(skb)->dev); | ||
535 | |||
536 | skb->dev = net->loopback_dev; | ||
537 | } | ||
533 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); | 538 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); |
534 | else | 539 | } else |
535 | #endif | 540 | #endif |
536 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); | 541 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); |
537 | 542 | ||
@@ -1065,57 +1070,61 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af) | |||
1065 | */ | 1070 | */ |
1066 | cp = pp->conn_out_get(af, skb, pp, &iph, iph.len, 0); | 1071 | cp = pp->conn_out_get(af, skb, pp, &iph, iph.len, 0); |
1067 | 1072 | ||
1068 | if (unlikely(!cp)) { | 1073 | if (likely(cp)) |
1069 | if (sysctl_ip_vs_nat_icmp_send && | 1074 | return handle_response(af, skb, pp, cp, iph.len); |
1070 | (pp->protocol == IPPROTO_TCP || | 1075 | if (sysctl_ip_vs_nat_icmp_send && |
1071 | pp->protocol == IPPROTO_UDP || | 1076 | (pp->protocol == IPPROTO_TCP || |
1072 | pp->protocol == IPPROTO_SCTP)) { | 1077 | pp->protocol == IPPROTO_UDP || |
1073 | __be16 _ports[2], *pptr; | 1078 | pp->protocol == IPPROTO_SCTP)) { |
1074 | 1079 | __be16 _ports[2], *pptr; | |
1075 | pptr = skb_header_pointer(skb, iph.len, | 1080 | |
1076 | sizeof(_ports), _ports); | 1081 | pptr = skb_header_pointer(skb, iph.len, |
1077 | if (pptr == NULL) | 1082 | sizeof(_ports), _ports); |
1078 | return NF_ACCEPT; /* Not for me */ | 1083 | if (pptr == NULL) |
1079 | if (ip_vs_lookup_real_service(af, iph.protocol, | 1084 | return NF_ACCEPT; /* Not for me */ |
1080 | &iph.saddr, | 1085 | if (ip_vs_lookup_real_service(af, iph.protocol, |
1081 | pptr[0])) { | 1086 | &iph.saddr, |
1082 | /* | 1087 | pptr[0])) { |
1083 | * Notify the real server: there is no | 1088 | /* |
1084 | * existing entry if it is not RST | 1089 | * Notify the real server: there is no |
1085 | * packet or not TCP packet. | 1090 | * existing entry if it is not RST |
1086 | */ | 1091 | * packet or not TCP packet. |
1087 | if ((iph.protocol != IPPROTO_TCP && | 1092 | */ |
1088 | iph.protocol != IPPROTO_SCTP) | 1093 | if ((iph.protocol != IPPROTO_TCP && |
1089 | || ((iph.protocol == IPPROTO_TCP | 1094 | iph.protocol != IPPROTO_SCTP) |
1090 | && !is_tcp_reset(skb, iph.len)) | 1095 | || ((iph.protocol == IPPROTO_TCP |
1091 | || (iph.protocol == IPPROTO_SCTP | 1096 | && !is_tcp_reset(skb, iph.len)) |
1092 | && !is_sctp_abort(skb, | 1097 | || (iph.protocol == IPPROTO_SCTP |
1093 | iph.len)))) { | 1098 | && !is_sctp_abort(skb, |
1099 | iph.len)))) { | ||
1094 | #ifdef CONFIG_IP_VS_IPV6 | 1100 | #ifdef CONFIG_IP_VS_IPV6 |
1095 | if (af == AF_INET6) | 1101 | if (af == AF_INET6) { |
1096 | icmpv6_send(skb, | 1102 | struct net *net = |
1097 | ICMPV6_DEST_UNREACH, | 1103 | dev_net(skb_dst(skb)->dev); |
1098 | ICMPV6_PORT_UNREACH, | 1104 | |
1099 | 0); | 1105 | if (!skb->dev) |
1100 | else | 1106 | skb->dev = net->loopback_dev; |
1107 | icmpv6_send(skb, | ||
1108 | ICMPV6_DEST_UNREACH, | ||
1109 | ICMPV6_PORT_UNREACH, | ||
1110 | 0); | ||
1111 | } else | ||
1101 | #endif | 1112 | #endif |
1102 | icmp_send(skb, | 1113 | icmp_send(skb, |
1103 | ICMP_DEST_UNREACH, | 1114 | ICMP_DEST_UNREACH, |
1104 | ICMP_PORT_UNREACH, 0); | 1115 | ICMP_PORT_UNREACH, 0); |
1105 | return NF_DROP; | 1116 | return NF_DROP; |
1106 | } | ||
1107 | } | 1117 | } |
1108 | } | 1118 | } |
1109 | IP_VS_DBG_PKT(12, pp, skb, 0, | ||
1110 | "packet continues traversal as normal"); | ||
1111 | return NF_ACCEPT; | ||
1112 | } | 1119 | } |
1113 | 1120 | IP_VS_DBG_PKT(12, pp, skb, 0, | |
1114 | return handle_response(af, skb, pp, cp, iph.len); | 1121 | "ip_vs_out: packet continues traversal as normal"); |
1122 | return NF_ACCEPT; | ||
1115 | } | 1123 | } |
1116 | 1124 | ||
1117 | /* | 1125 | /* |
1118 | * It is hooked at the NF_INET_FORWARD chain, used only for VS/NAT. | 1126 | * It is hooked at the NF_INET_FORWARD and NF_INET_LOCAL_IN chain, |
1127 | * used only for VS/NAT. | ||
1119 | * Check if packet is reply for established ip_vs_conn. | 1128 | * Check if packet is reply for established ip_vs_conn. |
1120 | */ | 1129 | */ |
1121 | static unsigned int | 1130 | static unsigned int |
@@ -1147,7 +1156,8 @@ ip_vs_local_reply4(unsigned int hooknum, struct sk_buff *skb, | |||
1147 | #ifdef CONFIG_IP_VS_IPV6 | 1156 | #ifdef CONFIG_IP_VS_IPV6 |
1148 | 1157 | ||
1149 | /* | 1158 | /* |
1150 | * It is hooked at the NF_INET_FORWARD chain, used only for VS/NAT. | 1159 | * It is hooked at the NF_INET_FORWARD and NF_INET_LOCAL_IN chain, |
1160 | * used only for VS/NAT. | ||
1151 | * Check if packet is reply for established ip_vs_conn. | 1161 | * Check if packet is reply for established ip_vs_conn. |
1152 | */ | 1162 | */ |
1153 | static unsigned int | 1163 | static unsigned int |
@@ -1404,34 +1414,43 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
1404 | * and send it on its way... | 1414 | * and send it on its way... |
1405 | */ | 1415 | */ |
1406 | static unsigned int | 1416 | static unsigned int |
1407 | ip_vs_in(unsigned int hooknum, struct sk_buff *skb, | 1417 | ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) |
1408 | const struct net_device *in, const struct net_device *out, | ||
1409 | int (*okfn)(struct sk_buff *)) | ||
1410 | { | 1418 | { |
1411 | struct ip_vs_iphdr iph; | 1419 | struct ip_vs_iphdr iph; |
1412 | struct ip_vs_protocol *pp; | 1420 | struct ip_vs_protocol *pp; |
1413 | struct ip_vs_conn *cp; | 1421 | struct ip_vs_conn *cp; |
1414 | int ret, restart, af, pkts; | 1422 | int ret, restart, pkts; |
1415 | 1423 | ||
1416 | /* Already marked as IPVS request or reply? */ | 1424 | /* Already marked as IPVS request or reply? */ |
1417 | if (skb->ipvs_property) | 1425 | if (skb->ipvs_property) |
1418 | return NF_ACCEPT; | 1426 | return NF_ACCEPT; |
1419 | 1427 | ||
1420 | af = (skb->protocol == htons(ETH_P_IP)) ? AF_INET : AF_INET6; | ||
1421 | |||
1422 | ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); | ||
1423 | |||
1424 | /* | 1428 | /* |
1425 | * Big tappo: only PACKET_HOST, including loopback for local client | 1429 | * Big tappo: |
1426 | * Don't handle local packets on IPv6 for now | 1430 | * - remote client: only PACKET_HOST |
1431 | * - route: used for struct net when skb->dev is unset | ||
1427 | */ | 1432 | */ |
1428 | if (unlikely(skb->pkt_type != PACKET_HOST)) { | 1433 | if (unlikely((skb->pkt_type != PACKET_HOST && |
1429 | IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n", | 1434 | hooknum != NF_INET_LOCAL_OUT) || |
1430 | skb->pkt_type, | 1435 | !skb_dst(skb))) { |
1431 | iph.protocol, | 1436 | ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); |
1432 | IP_VS_DBG_ADDR(af, &iph.daddr)); | 1437 | IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s" |
1438 | " ignored in hook %u\n", | ||
1439 | skb->pkt_type, iph.protocol, | ||
1440 | IP_VS_DBG_ADDR(af, &iph.daddr), hooknum); | ||
1433 | return NF_ACCEPT; | 1441 | return NF_ACCEPT; |
1434 | } | 1442 | } |
1443 | ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); | ||
1444 | |||
1445 | /* Bad... Do not break raw sockets */ | ||
1446 | if (unlikely(skb->sk != NULL && hooknum == NF_INET_LOCAL_OUT && | ||
1447 | af == AF_INET)) { | ||
1448 | struct sock *sk = skb->sk; | ||
1449 | struct inet_sock *inet = inet_sk(skb->sk); | ||
1450 | |||
1451 | if (inet && sk->sk_family == PF_INET && inet->nodefrag) | ||
1452 | return NF_ACCEPT; | ||
1453 | } | ||
1435 | 1454 | ||
1436 | #ifdef CONFIG_IP_VS_IPV6 | 1455 | #ifdef CONFIG_IP_VS_IPV6 |
1437 | if (af == AF_INET6) { | 1456 | if (af == AF_INET6) { |
@@ -1467,11 +1486,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, | |||
1467 | if (unlikely(!cp)) { | 1486 | if (unlikely(!cp)) { |
1468 | int v; | 1487 | int v; |
1469 | 1488 | ||
1470 | /* For local client packets, it could be a response */ | ||
1471 | cp = pp->conn_out_get(af, skb, pp, &iph, iph.len, 0); | ||
1472 | if (cp) | ||
1473 | return handle_response(af, skb, pp, cp, iph.len); | ||
1474 | |||
1475 | if (!pp->conn_schedule(af, skb, pp, &v, &cp)) | 1489 | if (!pp->conn_schedule(af, skb, pp, &v, &cp)) |
1476 | return v; | 1490 | return v; |
1477 | } | 1491 | } |
@@ -1479,7 +1493,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, | |||
1479 | if (unlikely(!cp)) { | 1493 | if (unlikely(!cp)) { |
1480 | /* sorry, all this trouble for a no-hit :) */ | 1494 | /* sorry, all this trouble for a no-hit :) */ |
1481 | IP_VS_DBG_PKT(12, pp, skb, 0, | 1495 | IP_VS_DBG_PKT(12, pp, skb, 0, |
1482 | "packet continues traversal as normal"); | 1496 | "ip_vs_in: packet continues traversal as normal"); |
1483 | return NF_ACCEPT; | 1497 | return NF_ACCEPT; |
1484 | } | 1498 | } |
1485 | 1499 | ||
@@ -1550,6 +1564,72 @@ out: | |||
1550 | return ret; | 1564 | return ret; |
1551 | } | 1565 | } |
1552 | 1566 | ||
1567 | /* | ||
1568 | * AF_INET handler in NF_INET_LOCAL_IN chain | ||
1569 | * Schedule and forward packets from remote clients | ||
1570 | */ | ||
1571 | static unsigned int | ||
1572 | ip_vs_remote_request4(unsigned int hooknum, struct sk_buff *skb, | ||
1573 | const struct net_device *in, | ||
1574 | const struct net_device *out, | ||
1575 | int (*okfn)(struct sk_buff *)) | ||
1576 | { | ||
1577 | return ip_vs_in(hooknum, skb, AF_INET); | ||
1578 | } | ||
1579 | |||
1580 | /* | ||
1581 | * AF_INET handler in NF_INET_LOCAL_OUT chain | ||
1582 | * Schedule and forward packets from local clients | ||
1583 | */ | ||
1584 | static unsigned int | ||
1585 | ip_vs_local_request4(unsigned int hooknum, struct sk_buff *skb, | ||
1586 | const struct net_device *in, const struct net_device *out, | ||
1587 | int (*okfn)(struct sk_buff *)) | ||
1588 | { | ||
1589 | unsigned int verdict; | ||
1590 | |||
1591 | /* Disable BH in LOCAL_OUT until all places are fixed */ | ||
1592 | local_bh_disable(); | ||
1593 | verdict = ip_vs_in(hooknum, skb, AF_INET); | ||
1594 | local_bh_enable(); | ||
1595 | return verdict; | ||
1596 | } | ||
1597 | |||
1598 | #ifdef CONFIG_IP_VS_IPV6 | ||
1599 | |||
1600 | /* | ||
1601 | * AF_INET6 handler in NF_INET_LOCAL_IN chain | ||
1602 | * Schedule and forward packets from remote clients | ||
1603 | */ | ||
1604 | static unsigned int | ||
1605 | ip_vs_remote_request6(unsigned int hooknum, struct sk_buff *skb, | ||
1606 | const struct net_device *in, | ||
1607 | const struct net_device *out, | ||
1608 | int (*okfn)(struct sk_buff *)) | ||
1609 | { | ||
1610 | return ip_vs_in(hooknum, skb, AF_INET6); | ||
1611 | } | ||
1612 | |||
1613 | /* | ||
1614 | * AF_INET6 handler in NF_INET_LOCAL_OUT chain | ||
1615 | * Schedule and forward packets from local clients | ||
1616 | */ | ||
1617 | static unsigned int | ||
1618 | ip_vs_local_request6(unsigned int hooknum, struct sk_buff *skb, | ||
1619 | const struct net_device *in, const struct net_device *out, | ||
1620 | int (*okfn)(struct sk_buff *)) | ||
1621 | { | ||
1622 | unsigned int verdict; | ||
1623 | |||
1624 | /* Disable BH in LOCAL_OUT until all places are fixed */ | ||
1625 | local_bh_disable(); | ||
1626 | verdict = ip_vs_in(hooknum, skb, AF_INET6); | ||
1627 | local_bh_enable(); | ||
1628 | return verdict; | ||
1629 | } | ||
1630 | |||
1631 | #endif | ||
1632 | |||
1553 | 1633 | ||
1554 | /* | 1634 | /* |
1555 | * It is hooked at the NF_INET_FORWARD chain, in order to catch ICMP | 1635 | * It is hooked at the NF_INET_FORWARD chain, in order to catch ICMP |
@@ -1590,15 +1670,23 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb, | |||
1590 | 1670 | ||
1591 | 1671 | ||
1592 | static struct nf_hook_ops ip_vs_ops[] __read_mostly = { | 1672 | static struct nf_hook_ops ip_vs_ops[] __read_mostly = { |
1673 | /* After packet filtering, change source only for VS/NAT */ | ||
1674 | { | ||
1675 | .hook = ip_vs_reply4, | ||
1676 | .owner = THIS_MODULE, | ||
1677 | .pf = PF_INET, | ||
1678 | .hooknum = NF_INET_LOCAL_IN, | ||
1679 | .priority = 99, | ||
1680 | }, | ||
1593 | /* After packet filtering, forward packet through VS/DR, VS/TUN, | 1681 | /* After packet filtering, forward packet through VS/DR, VS/TUN, |
1594 | * or VS/NAT(change destination), so that filtering rules can be | 1682 | * or VS/NAT(change destination), so that filtering rules can be |
1595 | * applied to IPVS. */ | 1683 | * applied to IPVS. */ |
1596 | { | 1684 | { |
1597 | .hook = ip_vs_in, | 1685 | .hook = ip_vs_remote_request4, |
1598 | .owner = THIS_MODULE, | 1686 | .owner = THIS_MODULE, |
1599 | .pf = PF_INET, | 1687 | .pf = PF_INET, |
1600 | .hooknum = NF_INET_LOCAL_IN, | 1688 | .hooknum = NF_INET_LOCAL_IN, |
1601 | .priority = 100, | 1689 | .priority = 101, |
1602 | }, | 1690 | }, |
1603 | /* Before ip_vs_in, change source only for VS/NAT */ | 1691 | /* Before ip_vs_in, change source only for VS/NAT */ |
1604 | { | 1692 | { |
@@ -1608,14 +1696,22 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = { | |||
1608 | .hooknum = NF_INET_LOCAL_OUT, | 1696 | .hooknum = NF_INET_LOCAL_OUT, |
1609 | .priority = -99, | 1697 | .priority = -99, |
1610 | }, | 1698 | }, |
1699 | /* After mangle, schedule and forward local requests */ | ||
1700 | { | ||
1701 | .hook = ip_vs_local_request4, | ||
1702 | .owner = THIS_MODULE, | ||
1703 | .pf = PF_INET, | ||
1704 | .hooknum = NF_INET_LOCAL_OUT, | ||
1705 | .priority = -98, | ||
1706 | }, | ||
1611 | /* After packet filtering (but before ip_vs_out_icmp), catch icmp | 1707 | /* After packet filtering (but before ip_vs_out_icmp), catch icmp |
1612 | * destined for 0.0.0.0/0, which is for incoming IPVS connections */ | 1708 | * destined for 0.0.0.0/0, which is for incoming IPVS connections */ |
1613 | { | 1709 | { |
1614 | .hook = ip_vs_forward_icmp, | 1710 | .hook = ip_vs_forward_icmp, |
1615 | .owner = THIS_MODULE, | 1711 | .owner = THIS_MODULE, |
1616 | .pf = PF_INET, | 1712 | .pf = PF_INET, |
1617 | .hooknum = NF_INET_FORWARD, | 1713 | .hooknum = NF_INET_FORWARD, |
1618 | .priority = 99, | 1714 | .priority = 99, |
1619 | }, | 1715 | }, |
1620 | /* After packet filtering, change source only for VS/NAT */ | 1716 | /* After packet filtering, change source only for VS/NAT */ |
1621 | { | 1717 | { |
@@ -1626,15 +1722,23 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = { | |||
1626 | .priority = 100, | 1722 | .priority = 100, |
1627 | }, | 1723 | }, |
1628 | #ifdef CONFIG_IP_VS_IPV6 | 1724 | #ifdef CONFIG_IP_VS_IPV6 |
1725 | /* After packet filtering, change source only for VS/NAT */ | ||
1726 | { | ||
1727 | .hook = ip_vs_reply6, | ||
1728 | .owner = THIS_MODULE, | ||
1729 | .pf = PF_INET6, | ||
1730 | .hooknum = NF_INET_LOCAL_IN, | ||
1731 | .priority = 99, | ||
1732 | }, | ||
1629 | /* After packet filtering, forward packet through VS/DR, VS/TUN, | 1733 | /* After packet filtering, forward packet through VS/DR, VS/TUN, |
1630 | * or VS/NAT(change destination), so that filtering rules can be | 1734 | * or VS/NAT(change destination), so that filtering rules can be |
1631 | * applied to IPVS. */ | 1735 | * applied to IPVS. */ |
1632 | { | 1736 | { |
1633 | .hook = ip_vs_in, | 1737 | .hook = ip_vs_remote_request6, |
1634 | .owner = THIS_MODULE, | 1738 | .owner = THIS_MODULE, |
1635 | .pf = PF_INET6, | 1739 | .pf = PF_INET6, |
1636 | .hooknum = NF_INET_LOCAL_IN, | 1740 | .hooknum = NF_INET_LOCAL_IN, |
1637 | .priority = 100, | 1741 | .priority = 101, |
1638 | }, | 1742 | }, |
1639 | /* Before ip_vs_in, change source only for VS/NAT */ | 1743 | /* Before ip_vs_in, change source only for VS/NAT */ |
1640 | { | 1744 | { |
@@ -1644,14 +1748,22 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = { | |||
1644 | .hooknum = NF_INET_LOCAL_OUT, | 1748 | .hooknum = NF_INET_LOCAL_OUT, |
1645 | .priority = -99, | 1749 | .priority = -99, |
1646 | }, | 1750 | }, |
1751 | /* After mangle, schedule and forward local requests */ | ||
1752 | { | ||
1753 | .hook = ip_vs_local_request6, | ||
1754 | .owner = THIS_MODULE, | ||
1755 | .pf = PF_INET6, | ||
1756 | .hooknum = NF_INET_LOCAL_OUT, | ||
1757 | .priority = -98, | ||
1758 | }, | ||
1647 | /* After packet filtering (but before ip_vs_out_icmp), catch icmp | 1759 | /* After packet filtering (but before ip_vs_out_icmp), catch icmp |
1648 | * destined for 0.0.0.0/0, which is for incoming IPVS connections */ | 1760 | * destined for 0.0.0.0/0, which is for incoming IPVS connections */ |
1649 | { | 1761 | { |
1650 | .hook = ip_vs_forward_icmp_v6, | 1762 | .hook = ip_vs_forward_icmp_v6, |
1651 | .owner = THIS_MODULE, | 1763 | .owner = THIS_MODULE, |
1652 | .pf = PF_INET6, | 1764 | .pf = PF_INET6, |
1653 | .hooknum = NF_INET_FORWARD, | 1765 | .hooknum = NF_INET_FORWARD, |
1654 | .priority = 99, | 1766 | .priority = 99, |
1655 | }, | 1767 | }, |
1656 | /* After packet filtering, change source only for VS/NAT */ | 1768 | /* After packet filtering, change source only for VS/NAT */ |
1657 | { | 1769 | { |
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 8608882f89e3..97b5361c036e 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c | |||
@@ -11,6 +11,16 @@ | |||
11 | * | 11 | * |
12 | * Changes: | 12 | * Changes: |
13 | * | 13 | * |
14 | * Description of forwarding methods: | ||
15 | * - all transmitters are called from LOCAL_IN (remote clients) and | ||
16 | * LOCAL_OUT (local clients) but for ICMP can be called from FORWARD | ||
17 | * - not all connections have destination server, for example, | ||
18 | * connections in backup server when fwmark is used | ||
19 | * - bypass connections use daddr from packet | ||
20 | * LOCAL_OUT rules: | ||
21 | * - skb->dev is NULL, skb->protocol is not set (both are set in POST_ROUTING) | ||
22 | * - skb->pkt_type is not set yet | ||
23 | * - the only place where we can see skb->sk != NULL | ||
14 | */ | 24 | */ |
15 | 25 | ||
16 | #define KMSG_COMPONENT "IPVS" | 26 | #define KMSG_COMPONENT "IPVS" |
@@ -452,8 +462,13 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
452 | /* MTU checking */ | 462 | /* MTU checking */ |
453 | mtu = dst_mtu(&rt->dst); | 463 | mtu = dst_mtu(&rt->dst); |
454 | if (skb->len > mtu) { | 464 | if (skb->len > mtu) { |
455 | dst_release(&rt->dst); | 465 | if (!skb->dev) { |
466 | struct net *net = dev_net(skb_dst(skb)->dev); | ||
467 | |||
468 | skb->dev = net->loopback_dev; | ||
469 | } | ||
456 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 470 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
471 | dst_release(&rt->dst); | ||
457 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); | 472 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); |
458 | goto tx_error; | 473 | goto tx_error; |
459 | } | 474 | } |
@@ -659,6 +674,11 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
659 | /* MTU checking */ | 674 | /* MTU checking */ |
660 | mtu = dst_mtu(&rt->dst); | 675 | mtu = dst_mtu(&rt->dst); |
661 | if (skb->len > mtu) { | 676 | if (skb->len > mtu) { |
677 | if (!skb->dev) { | ||
678 | struct net *net = dev_net(skb_dst(skb)->dev); | ||
679 | |||
680 | skb->dev = net->loopback_dev; | ||
681 | } | ||
662 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 682 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
663 | IP_VS_DBG_RL_PKT(0, pp, skb, 0, | 683 | IP_VS_DBG_RL_PKT(0, pp, skb, 0, |
664 | "ip_vs_nat_xmit_v6(): frag needed for"); | 684 | "ip_vs_nat_xmit_v6(): frag needed for"); |
@@ -748,13 +768,6 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
748 | 768 | ||
749 | EnterFunction(10); | 769 | EnterFunction(10); |
750 | 770 | ||
751 | if (skb->protocol != htons(ETH_P_IP)) { | ||
752 | IP_VS_DBG_RL("%s(): protocol error, " | ||
753 | "ETH_P_IP: %d, skb protocol: %d\n", | ||
754 | __func__, htons(ETH_P_IP), skb->protocol); | ||
755 | goto tx_error; | ||
756 | } | ||
757 | |||
758 | if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, | 771 | if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, |
759 | RT_TOS(tos), 1|2))) | 772 | RT_TOS(tos), 1|2))) |
760 | goto tx_error_icmp; | 773 | goto tx_error_icmp; |
@@ -869,13 +882,6 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
869 | 882 | ||
870 | EnterFunction(10); | 883 | EnterFunction(10); |
871 | 884 | ||
872 | if (skb->protocol != htons(ETH_P_IPV6)) { | ||
873 | IP_VS_DBG_RL("%s(): protocol error, " | ||
874 | "ETH_P_IPV6: %d, skb protocol: %d\n", | ||
875 | __func__, htons(ETH_P_IPV6), skb->protocol); | ||
876 | goto tx_error; | ||
877 | } | ||
878 | |||
879 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, | 885 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, |
880 | &saddr, 1, 1|2))) | 886 | &saddr, 1, 1|2))) |
881 | goto tx_error_icmp; | 887 | goto tx_error_icmp; |
@@ -896,6 +902,11 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
896 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); | 902 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); |
897 | 903 | ||
898 | if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) { | 904 | if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) { |
905 | if (!skb->dev) { | ||
906 | struct net *net = dev_net(skb_dst(skb)->dev); | ||
907 | |||
908 | skb->dev = net->loopback_dev; | ||
909 | } | ||
899 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 910 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
900 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); | 911 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); |
901 | goto tx_error_put; | 912 | goto tx_error_put; |
@@ -1053,6 +1064,11 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1053 | /* MTU checking */ | 1064 | /* MTU checking */ |
1054 | mtu = dst_mtu(&rt->dst); | 1065 | mtu = dst_mtu(&rt->dst); |
1055 | if (skb->len > mtu) { | 1066 | if (skb->len > mtu) { |
1067 | if (!skb->dev) { | ||
1068 | struct net *net = dev_net(skb_dst(skb)->dev); | ||
1069 | |||
1070 | skb->dev = net->loopback_dev; | ||
1071 | } | ||
1056 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 1072 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
1057 | dst_release(&rt->dst); | 1073 | dst_release(&rt->dst); |
1058 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); | 1074 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); |
@@ -1271,6 +1287,11 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1271 | /* MTU checking */ | 1287 | /* MTU checking */ |
1272 | mtu = dst_mtu(&rt->dst); | 1288 | mtu = dst_mtu(&rt->dst); |
1273 | if (skb->len > mtu) { | 1289 | if (skb->len > mtu) { |
1290 | if (!skb->dev) { | ||
1291 | struct net *net = dev_net(skb_dst(skb)->dev); | ||
1292 | |||
1293 | skb->dev = net->loopback_dev; | ||
1294 | } | ||
1274 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 1295 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
1275 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); | 1296 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); |
1276 | goto tx_error_put; | 1297 | goto tx_error_put; |