aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c56
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_sctp.c11
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_tcp.c10
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_udp.c10
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
180static inline void 180static inline int
181ip_vs_conn_fill_param_persist(const struct ip_vs_service *svc, 181ip_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,
200static struct ip_vs_conn * 202static struct ip_vs_conn *
201ip_vs_sched_persist(struct ip_vs_service *svc, 203ip_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, &param); 274 if (ip_vs_conn_fill_param_persist(svc, skb, protocol, &snet, 0,
275 vaddr, vport, &param) < 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(&param); 282 ct = ip_vs_ct_in_get(&param);
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(&param, &dest->addr, dport, flags, dest, skb->mark); 333 cp = ip_vs_conn_new(&param, &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 */
346struct ip_vs_conn * 372struct ip_vs_conn *
347ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, 373ip_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