|
|
@@ -36,23 +36,32 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
|
|
|
struct net *net;
|
|
|
struct ip_vs_service *svc;
|
|
|
struct udphdr _udph, *uh;
|
|
|
+ __be16 _ports[2], *ports = NULL;
|
|
|
|
|
|
- if (ip_vs_iph_icmp(iph)) {
|
|
|
- /* TEMPORARY - do not schedule icmp yet */
|
|
|
- *verdict = NF_ACCEPT;
|
|
|
- return 0;
|
|
|
+ if (likely(!ip_vs_iph_icmp(iph))) {
|
|
|
+ /* IPv6 fragments, only first fragment will hit this */
|
|
|
+ uh = skb_header_pointer(skb, iph->len, sizeof(_udph), &_udph);
|
|
|
+ if (uh)
|
|
|
+ ports = &uh->source;
|
|
|
+ } else {
|
|
|
+ ports = skb_header_pointer(
|
|
|
+ skb, iph->len, sizeof(_ports), &_ports);
|
|
|
}
|
|
|
|
|
|
- /* IPv6 fragments, only first fragment will hit this */
|
|
|
- uh = skb_header_pointer(skb, iph->len, sizeof(_udph), &_udph);
|
|
|
- if (uh == NULL) {
|
|
|
+ if (!ports) {
|
|
|
*verdict = NF_DROP;
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
net = skb_net(skb);
|
|
|
rcu_read_lock();
|
|
|
- svc = ip_vs_service_find(net, af, skb->mark, iph->protocol,
|
|
|
- &iph->daddr, uh->dest);
|
|
|
+ if (likely(!ip_vs_iph_inverse(iph)))
|
|
|
+ svc = ip_vs_service_find(net, af, skb->mark, iph->protocol,
|
|
|
+ &iph->daddr, ports[1]);
|
|
|
+ else
|
|
|
+ svc = ip_vs_service_find(net, af, skb->mark, iph->protocol,
|
|
|
+ &iph->saddr, ports[0]);
|
|
|
+
|
|
|
if (svc) {
|
|
|
int ignored;
|
|
|
|