diff options
-rw-r--r-- | net/netfilter/ipvs/ip_vs_core.c | 56 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_sctp.c | 11 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_tcp.c | 10 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_udp.c | 10 |
4 files changed, 64 insertions, 23 deletions
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 9acdd79a4a05..3445da6e8c95 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c | |||
@@ -177,7 +177,7 @@ ip_vs_set_state(struct ip_vs_conn *cp, int direction, | |||
177 | return pp->state_transition(cp, direction, skb, pp); | 177 | return pp->state_transition(cp, direction, skb, pp); |
178 | } | 178 | } |
179 | 179 | ||
180 | static inline void | 180 | static inline int |
181 | ip_vs_conn_fill_param_persist(const struct ip_vs_service *svc, | 181 | ip_vs_conn_fill_param_persist(const struct ip_vs_service *svc, |
182 | struct sk_buff *skb, int protocol, | 182 | struct sk_buff *skb, int protocol, |
183 | const union nf_inet_addr *caddr, __be16 cport, | 183 | const union nf_inet_addr *caddr, __be16 cport, |
@@ -187,7 +187,9 @@ ip_vs_conn_fill_param_persist(const struct ip_vs_service *svc, | |||
187 | ip_vs_conn_fill_param(svc->af, protocol, caddr, cport, vaddr, vport, p); | 187 | ip_vs_conn_fill_param(svc->af, protocol, caddr, cport, vaddr, vport, p); |
188 | p->pe = svc->pe; | 188 | p->pe = svc->pe; |
189 | if (p->pe && p->pe->fill_param) | 189 | if (p->pe && p->pe->fill_param) |
190 | p->pe->fill_param(p, skb); | 190 | return p->pe->fill_param(p, skb); |
191 | |||
192 | return 0; | ||
191 | } | 193 | } |
192 | 194 | ||
193 | /* | 195 | /* |
@@ -200,7 +202,7 @@ ip_vs_conn_fill_param_persist(const struct ip_vs_service *svc, | |||
200 | static struct ip_vs_conn * | 202 | static struct ip_vs_conn * |
201 | ip_vs_sched_persist(struct ip_vs_service *svc, | 203 | ip_vs_sched_persist(struct ip_vs_service *svc, |
202 | struct sk_buff *skb, | 204 | struct sk_buff *skb, |
203 | __be16 src_port, __be16 dst_port) | 205 | __be16 src_port, __be16 dst_port, int *ignored) |
204 | { | 206 | { |
205 | struct ip_vs_conn *cp = NULL; | 207 | struct ip_vs_conn *cp = NULL; |
206 | struct ip_vs_iphdr iph; | 208 | struct ip_vs_iphdr iph; |
@@ -268,20 +270,27 @@ ip_vs_sched_persist(struct ip_vs_service *svc, | |||
268 | vaddr = &fwmark; | 270 | vaddr = &fwmark; |
269 | } | 271 | } |
270 | } | 272 | } |
271 | ip_vs_conn_fill_param_persist(svc, skb, protocol, &snet, 0, | 273 | /* return *ignored = -1 so NF_DROP can be used */ |
272 | vaddr, vport, ¶m); | 274 | if (ip_vs_conn_fill_param_persist(svc, skb, protocol, &snet, 0, |
275 | vaddr, vport, ¶m) < 0) { | ||
276 | *ignored = -1; | ||
277 | return NULL; | ||
278 | } | ||
273 | } | 279 | } |
274 | 280 | ||
275 | /* Check if a template already exists */ | 281 | /* Check if a template already exists */ |
276 | ct = ip_vs_ct_in_get(¶m); | 282 | ct = ip_vs_ct_in_get(¶m); |
277 | if (!ct || !ip_vs_check_template(ct)) { | 283 | if (!ct || !ip_vs_check_template(ct)) { |
278 | /* No template found or the dest of the connection | 284 | /* |
285 | * No template found or the dest of the connection | ||
279 | * template is not available. | 286 | * template is not available. |
287 | * return *ignored=0 i.e. ICMP and NF_DROP | ||
280 | */ | 288 | */ |
281 | dest = svc->scheduler->schedule(svc, skb); | 289 | dest = svc->scheduler->schedule(svc, skb); |
282 | if (!dest) { | 290 | if (!dest) { |
283 | IP_VS_DBG(1, "p-schedule: no dest found.\n"); | 291 | IP_VS_DBG(1, "p-schedule: no dest found.\n"); |
284 | kfree(param.pe_data); | 292 | kfree(param.pe_data); |
293 | *ignored = 0; | ||
285 | return NULL; | 294 | return NULL; |
286 | } | 295 | } |
287 | 296 | ||
@@ -296,6 +305,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc, | |||
296 | IP_VS_CONN_F_TEMPLATE, dest, skb->mark); | 305 | IP_VS_CONN_F_TEMPLATE, dest, skb->mark); |
297 | if (ct == NULL) { | 306 | if (ct == NULL) { |
298 | kfree(param.pe_data); | 307 | kfree(param.pe_data); |
308 | *ignored = -1; | ||
299 | return NULL; | 309 | return NULL; |
300 | } | 310 | } |
301 | 311 | ||
@@ -323,6 +333,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc, | |||
323 | cp = ip_vs_conn_new(¶m, &dest->addr, dport, flags, dest, skb->mark); | 333 | cp = ip_vs_conn_new(¶m, &dest->addr, dport, flags, dest, skb->mark); |
324 | if (cp == NULL) { | 334 | if (cp == NULL) { |
325 | ip_vs_conn_put(ct); | 335 | ip_vs_conn_put(ct); |
336 | *ignored = -1; | ||
326 | return NULL; | 337 | return NULL; |
327 | } | 338 | } |
328 | 339 | ||
@@ -342,6 +353,21 @@ ip_vs_sched_persist(struct ip_vs_service *svc, | |||
342 | * It selects a server according to the virtual service, and | 353 | * It selects a server according to the virtual service, and |
343 | * creates a connection entry. | 354 | * creates a connection entry. |
344 | * Protocols supported: TCP, UDP | 355 | * Protocols supported: TCP, UDP |
356 | * | ||
357 | * Usage of *ignored | ||
358 | * | ||
359 | * 1 : protocol tried to schedule (eg. on SYN), found svc but the | ||
360 | * svc/scheduler decides that this packet should be accepted with | ||
361 | * NF_ACCEPT because it must not be scheduled. | ||
362 | * | ||
363 | * 0 : scheduler can not find destination, so try bypass or | ||
364 | * return ICMP and then NF_DROP (ip_vs_leave). | ||
365 | * | ||
366 | * -1 : scheduler tried to schedule but fatal error occurred, eg. | ||
367 | * ip_vs_conn_new failure (ENOMEM) or ip_vs_sip_fill_param | ||
368 | * failure such as missing Call-ID, ENOMEM on skb_linearize | ||
369 | * or pe_data. In this case we should return NF_DROP without | ||
370 | * any attempts to send ICMP with ip_vs_leave. | ||
345 | */ | 371 | */ |
346 | struct ip_vs_conn * | 372 | struct ip_vs_conn * |
347 | ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, | 373 | ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, |
@@ -372,11 +398,9 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, | |||
372 | } | 398 | } |
373 | 399 | ||
374 | /* | 400 | /* |
375 | * Do not schedule replies from local real server. It is risky | 401 | * Do not schedule replies from local real server. |
376 | * for fwmark services but mostly for persistent services. | ||
377 | */ | 402 | */ |
378 | if ((!skb->dev || skb->dev->flags & IFF_LOOPBACK) && | 403 | if ((!skb->dev || skb->dev->flags & IFF_LOOPBACK) && |
379 | (svc->flags & IP_VS_SVC_F_PERSISTENT || svc->fwmark) && | ||
380 | (cp = pp->conn_in_get(svc->af, skb, pp, &iph, iph.len, 1))) { | 404 | (cp = pp->conn_in_get(svc->af, skb, pp, &iph, iph.len, 1))) { |
381 | IP_VS_DBG_PKT(12, svc->af, pp, skb, 0, | 405 | IP_VS_DBG_PKT(12, svc->af, pp, skb, 0, |
382 | "Not scheduling reply for existing connection"); | 406 | "Not scheduling reply for existing connection"); |
@@ -387,10 +411,10 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, | |||
387 | /* | 411 | /* |
388 | * Persistent service | 412 | * Persistent service |
389 | */ | 413 | */ |
390 | if (svc->flags & IP_VS_SVC_F_PERSISTENT) { | 414 | if (svc->flags & IP_VS_SVC_F_PERSISTENT) |
391 | *ignored = 0; | 415 | return ip_vs_sched_persist(svc, skb, pptr[0], pptr[1], ignored); |
392 | return ip_vs_sched_persist(svc, skb, pptr[0], pptr[1]); | 416 | |
393 | } | 417 | *ignored = 0; |
394 | 418 | ||
395 | /* | 419 | /* |
396 | * Non-persistent service | 420 | * Non-persistent service |
@@ -403,8 +427,6 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, | |||
403 | return NULL; | 427 | return NULL; |
404 | } | 428 | } |
405 | 429 | ||
406 | *ignored = 0; | ||
407 | |||
408 | dest = svc->scheduler->schedule(svc, skb); | 430 | dest = svc->scheduler->schedule(svc, skb); |
409 | if (dest == NULL) { | 431 | if (dest == NULL) { |
410 | IP_VS_DBG(1, "Schedule: no dest found.\n"); | 432 | IP_VS_DBG(1, "Schedule: no dest found.\n"); |
@@ -425,8 +447,10 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, | |||
425 | cp = ip_vs_conn_new(&p, &dest->addr, | 447 | cp = ip_vs_conn_new(&p, &dest->addr, |
426 | dest->port ? dest->port : pptr[1], | 448 | dest->port ? dest->port : pptr[1], |
427 | flags, dest, skb->mark); | 449 | flags, dest, skb->mark); |
428 | if (!cp) | 450 | if (!cp) { |
451 | *ignored = -1; | ||
429 | return NULL; | 452 | return NULL; |
453 | } | ||
430 | } | 454 | } |
431 | 455 | ||
432 | IP_VS_DBG_BUF(6, "Schedule fwd:%c c:%s:%u v:%s:%u " | 456 | IP_VS_DBG_BUF(6, "Schedule fwd:%c c:%s:%u v:%s:%u " |
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c index 1ea96bcd342b..a315159983ad 100644 --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c | |||
@@ -47,13 +47,18 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp, | |||
47 | * incoming connection, and create a connection entry. | 47 | * incoming connection, and create a connection entry. |
48 | */ | 48 | */ |
49 | *cpp = ip_vs_schedule(svc, skb, pp, &ignored); | 49 | *cpp = ip_vs_schedule(svc, skb, pp, &ignored); |
50 | if (!*cpp && !ignored) { | 50 | if (!*cpp && ignored <= 0) { |
51 | *verdict = ip_vs_leave(svc, skb, pp); | 51 | if (!ignored) |
52 | *verdict = ip_vs_leave(svc, skb, pp); | ||
53 | else { | ||
54 | ip_vs_service_put(svc); | ||
55 | *verdict = NF_DROP; | ||
56 | } | ||
52 | return 0; | 57 | return 0; |
53 | } | 58 | } |
54 | ip_vs_service_put(svc); | 59 | ip_vs_service_put(svc); |
55 | } | 60 | } |
56 | 61 | /* NF_ACCEPT */ | |
57 | return 1; | 62 | return 1; |
58 | } | 63 | } |
59 | 64 | ||
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c index f6c5200e2146..1cdab12abfef 100644 --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c | |||
@@ -64,12 +64,18 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp, | |||
64 | * incoming connection, and create a connection entry. | 64 | * incoming connection, and create a connection entry. |
65 | */ | 65 | */ |
66 | *cpp = ip_vs_schedule(svc, skb, pp, &ignored); | 66 | *cpp = ip_vs_schedule(svc, skb, pp, &ignored); |
67 | if (!*cpp && !ignored) { | 67 | if (!*cpp && ignored <= 0) { |
68 | *verdict = ip_vs_leave(svc, skb, pp); | 68 | if (!ignored) |
69 | *verdict = ip_vs_leave(svc, skb, pp); | ||
70 | else { | ||
71 | ip_vs_service_put(svc); | ||
72 | *verdict = NF_DROP; | ||
73 | } | ||
69 | return 0; | 74 | return 0; |
70 | } | 75 | } |
71 | ip_vs_service_put(svc); | 76 | ip_vs_service_put(svc); |
72 | } | 77 | } |
78 | /* NF_ACCEPT */ | ||
73 | return 1; | 79 | return 1; |
74 | } | 80 | } |
75 | 81 | ||
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c index 9d106a06bb0a..cd398de010cc 100644 --- a/net/netfilter/ipvs/ip_vs_proto_udp.c +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c | |||
@@ -63,12 +63,18 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp, | |||
63 | * incoming connection, and create a connection entry. | 63 | * incoming connection, and create a connection entry. |
64 | */ | 64 | */ |
65 | *cpp = ip_vs_schedule(svc, skb, pp, &ignored); | 65 | *cpp = ip_vs_schedule(svc, skb, pp, &ignored); |
66 | if (!*cpp && !ignored) { | 66 | if (!*cpp && ignored <= 0) { |
67 | *verdict = ip_vs_leave(svc, skb, pp); | 67 | if (!ignored) |
68 | *verdict = ip_vs_leave(svc, skb, pp); | ||
69 | else { | ||
70 | ip_vs_service_put(svc); | ||
71 | *verdict = NF_DROP; | ||
72 | } | ||
68 | return 0; | 73 | return 0; |
69 | } | 74 | } |
70 | ip_vs_service_put(svc); | 75 | ip_vs_service_put(svc); |
71 | } | 76 | } |
77 | /* NF_ACCEPT */ | ||
72 | return 1; | 78 | return 1; |
73 | } | 79 | } |
74 | 80 | ||