diff options
Diffstat (limited to 'net/netfilter/ipvs/ip_vs_proto_udp.c')
-rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_udp.c | 41 |
1 files changed, 18 insertions, 23 deletions
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c index 2fedb2dcb3d..503a842c90d 100644 --- a/net/netfilter/ipvs/ip_vs_proto_udp.c +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c | |||
@@ -30,23 +30,22 @@ | |||
30 | 30 | ||
31 | static int | 31 | static int |
32 | udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, | 32 | udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, |
33 | int *verdict, struct ip_vs_conn **cpp) | 33 | int *verdict, struct ip_vs_conn **cpp, |
34 | struct ip_vs_iphdr *iph) | ||
34 | { | 35 | { |
35 | struct net *net; | 36 | struct net *net; |
36 | struct ip_vs_service *svc; | 37 | struct ip_vs_service *svc; |
37 | struct udphdr _udph, *uh; | 38 | struct udphdr _udph, *uh; |
38 | struct ip_vs_iphdr iph; | ||
39 | 39 | ||
40 | ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); | 40 | /* IPv6 fragments, only first fragment will hit this */ |
41 | 41 | uh = skb_header_pointer(skb, iph->len, sizeof(_udph), &_udph); | |
42 | uh = skb_header_pointer(skb, iph.len, sizeof(_udph), &_udph); | ||
43 | if (uh == NULL) { | 42 | if (uh == NULL) { |
44 | *verdict = NF_DROP; | 43 | *verdict = NF_DROP; |
45 | return 0; | 44 | return 0; |
46 | } | 45 | } |
47 | net = skb_net(skb); | 46 | net = skb_net(skb); |
48 | svc = ip_vs_service_get(net, af, skb->mark, iph.protocol, | 47 | svc = ip_vs_service_get(net, af, skb->mark, iph->protocol, |
49 | &iph.daddr, uh->dest); | 48 | &iph->daddr, uh->dest); |
50 | if (svc) { | 49 | if (svc) { |
51 | int ignored; | 50 | int ignored; |
52 | 51 | ||
@@ -64,10 +63,10 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, | |||
64 | * Let the virtual server select a real server for the | 63 | * Let the virtual server select a real server for the |
65 | * incoming connection, and create a connection entry. | 64 | * incoming connection, and create a connection entry. |
66 | */ | 65 | */ |
67 | *cpp = ip_vs_schedule(svc, skb, pd, &ignored); | 66 | *cpp = ip_vs_schedule(svc, skb, pd, &ignored, iph); |
68 | if (!*cpp && ignored <= 0) { | 67 | if (!*cpp && ignored <= 0) { |
69 | if (!ignored) | 68 | if (!ignored) |
70 | *verdict = ip_vs_leave(svc, skb, pd); | 69 | *verdict = ip_vs_leave(svc, skb, pd, iph); |
71 | else { | 70 | else { |
72 | ip_vs_service_put(svc); | 71 | ip_vs_service_put(svc); |
73 | *verdict = NF_DROP; | 72 | *verdict = NF_DROP; |
@@ -125,20 +124,18 @@ udp_partial_csum_update(int af, struct udphdr *uhdr, | |||
125 | 124 | ||
126 | 125 | ||
127 | static int | 126 | static int |
128 | udp_snat_handler(struct sk_buff *skb, | 127 | udp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp, |
129 | struct ip_vs_protocol *pp, struct ip_vs_conn *cp) | 128 | struct ip_vs_conn *cp, struct ip_vs_iphdr *iph) |
130 | { | 129 | { |
131 | struct udphdr *udph; | 130 | struct udphdr *udph; |
132 | unsigned int udphoff; | 131 | unsigned int udphoff = iph->len; |
133 | int oldlen; | 132 | int oldlen; |
134 | int payload_csum = 0; | 133 | int payload_csum = 0; |
135 | 134 | ||
136 | #ifdef CONFIG_IP_VS_IPV6 | 135 | #ifdef CONFIG_IP_VS_IPV6 |
137 | if (cp->af == AF_INET6) | 136 | if (cp->af == AF_INET6 && iph->fragoffs) |
138 | udphoff = sizeof(struct ipv6hdr); | 137 | return 1; |
139 | else | ||
140 | #endif | 138 | #endif |
141 | udphoff = ip_hdrlen(skb); | ||
142 | oldlen = skb->len - udphoff; | 139 | oldlen = skb->len - udphoff; |
143 | 140 | ||
144 | /* csum_check requires unshared skb */ | 141 | /* csum_check requires unshared skb */ |
@@ -210,20 +207,18 @@ udp_snat_handler(struct sk_buff *skb, | |||
210 | 207 | ||
211 | 208 | ||
212 | static int | 209 | static int |
213 | udp_dnat_handler(struct sk_buff *skb, | 210 | udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp, |
214 | struct ip_vs_protocol *pp, struct ip_vs_conn *cp) | 211 | struct ip_vs_conn *cp, struct ip_vs_iphdr *iph) |
215 | { | 212 | { |
216 | struct udphdr *udph; | 213 | struct udphdr *udph; |
217 | unsigned int udphoff; | 214 | unsigned int udphoff = iph->len; |
218 | int oldlen; | 215 | int oldlen; |
219 | int payload_csum = 0; | 216 | int payload_csum = 0; |
220 | 217 | ||
221 | #ifdef CONFIG_IP_VS_IPV6 | 218 | #ifdef CONFIG_IP_VS_IPV6 |
222 | if (cp->af == AF_INET6) | 219 | if (cp->af == AF_INET6 && iph->fragoffs) |
223 | udphoff = sizeof(struct ipv6hdr); | 220 | return 1; |
224 | else | ||
225 | #endif | 221 | #endif |
226 | udphoff = ip_hdrlen(skb); | ||
227 | oldlen = skb->len - udphoff; | 222 | oldlen = skb->len - udphoff; |
228 | 223 | ||
229 | /* csum_check requires unshared skb */ | 224 | /* csum_check requires unshared skb */ |