diff options
| -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; |
