/[linux-patches]/genpatches-2.6/trunk/2.6.14-pre/1023_3_ipvs-ip_vs_ftp-breaks-connections.patch
Gentoo

Contents of /genpatches-2.6/trunk/2.6.14-pre/1023_3_ipvs-ip_vs_ftp-breaks-connections.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 175 - (show annotations) (download)
Sat Oct 8 10:49:55 2005 UTC (12 years, 11 months ago) by dsd
File size: 9239 byte(s)
Creating 2.6.14-pre branch from 2.6.13
1 From stable-bounces@linux.kernel.org Thu Sep 15 14:13:43 2005
2 From: Julian Anastasov <ja@ssi.bg>
3 To: stable@kernel.org
4 Subject: [PATCH] ipvs: ip_vs_ftp breaks connections using persistence
5
6 ip_vs_ftp when loaded can create NAT connections with unknown
7 client port for passive FTP. For such expectations we lookup with
8 cport=0 on incoming packet but it matches the format of the persistence
9 templates causing packets to other persistent virtual servers to be
10 forwarded to real server without creating connection. Later the
11 reply packets are treated as foreign and not SNAT-ed.
12
13 If the IPVS box serves both FTP and other services (eg. HTTP)
14 for the time we wait for first packet for the FTP data connections with
15 unknown client port (there can be many), other HTTP connections
16 that have nothing common to the FTP conn break, i.e. HTTP client
17 sends SYN to the virtual IP but the SYN+ACK is not NAT-ed properly
18 in IPVS box and the client box returns RST to real server IP. I.e.
19 the result can be 10% broken HTTP traffic if 10% of the time
20 there are passive FTP connections in connecting state. It hurts
21 only IPVS connections.
22
23 This patch changes the connection lookup for packets from
24 clients:
25
26 * introduce IP_VS_CONN_F_TEMPLATE connection flag to mark the
27 connection as template
28 * create new connection lookup function just for templates - ip_vs_ct_in_get
29 * make sure ip_vs_conn_in_get hits only connections with
30 IP_VS_CONN_F_NO_CPORT flag set when s_port is 0. By this way
31 we avoid returning template when looking for cport=0 (ftp)
32
33 Signed-off-by: Julian Anastasov <ja@ssi.bg>
34 Signed-off-by: Chris Wright <chrisw@osdl.org>
35 ---
36 include/net/ip_vs.h | 3 +++
37 net/ipv4/ipvs/ip_vs_conn.c | 41 ++++++++++++++++++++++++++++++++++++++---
38 net/ipv4/ipvs/ip_vs_core.c | 16 ++++++++--------
39 net/ipv4/ipvs/ip_vs_sync.c | 20 ++++++++++++++------
40 4 files changed, 63 insertions(+), 17 deletions(-)
41
42 Index: linux-2.6.13.y/include/net/ip_vs.h
43 ===================================================================
44 --- linux-2.6.13.y.orig/include/net/ip_vs.h
45 +++ linux-2.6.13.y/include/net/ip_vs.h
46 @@ -84,6 +84,7 @@
47 #define IP_VS_CONN_F_IN_SEQ 0x0400 /* must do input seq adjust */
48 #define IP_VS_CONN_F_SEQ_MASK 0x0600 /* in/out sequence mask */
49 #define IP_VS_CONN_F_NO_CPORT 0x0800 /* no client port set yet */
50 +#define IP_VS_CONN_F_TEMPLATE 0x1000 /* template, not connection */
51
52 /* Move it to better place one day, for now keep it unique */
53 #define NFC_IPVS_PROPERTY 0x10000
54 @@ -740,6 +741,8 @@ enum {
55
56 extern struct ip_vs_conn *ip_vs_conn_in_get
57 (int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
58 +extern struct ip_vs_conn *ip_vs_ct_in_get
59 +(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
60 extern struct ip_vs_conn *ip_vs_conn_out_get
61 (int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
62
63 Index: linux-2.6.13.y/net/ipv4/ipvs/ip_vs_conn.c
64 ===================================================================
65 --- linux-2.6.13.y.orig/net/ipv4/ipvs/ip_vs_conn.c
66 +++ linux-2.6.13.y/net/ipv4/ipvs/ip_vs_conn.c
67 @@ -196,6 +196,7 @@ static inline struct ip_vs_conn *__ip_vs
68 list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
69 if (s_addr==cp->caddr && s_port==cp->cport &&
70 d_port==cp->vport && d_addr==cp->vaddr &&
71 + ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
72 protocol==cp->protocol) {
73 /* HIT */
74 atomic_inc(&cp->refcnt);
75 @@ -227,6 +228,40 @@ struct ip_vs_conn *ip_vs_conn_in_get
76 return cp;
77 }
78
79 +/* Get reference to connection template */
80 +struct ip_vs_conn *ip_vs_ct_in_get
81 +(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
82 +{
83 + unsigned hash;
84 + struct ip_vs_conn *cp;
85 +
86 + hash = ip_vs_conn_hashkey(protocol, s_addr, s_port);
87 +
88 + ct_read_lock(hash);
89 +
90 + list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
91 + if (s_addr==cp->caddr && s_port==cp->cport &&
92 + d_port==cp->vport && d_addr==cp->vaddr &&
93 + cp->flags & IP_VS_CONN_F_TEMPLATE &&
94 + protocol==cp->protocol) {
95 + /* HIT */
96 + atomic_inc(&cp->refcnt);
97 + goto out;
98 + }
99 + }
100 + cp = NULL;
101 +
102 + out:
103 + ct_read_unlock(hash);
104 +
105 + IP_VS_DBG(7, "template lookup/in %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d %s\n",
106 + ip_vs_proto_name(protocol),
107 + NIPQUAD(s_addr), ntohs(s_port),
108 + NIPQUAD(d_addr), ntohs(d_port),
109 + cp?"hit":"not hit");
110 +
111 + return cp;
112 +}
113
114 /*
115 * Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
116 @@ -367,7 +402,7 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, s
117 atomic_read(&dest->refcnt));
118
119 /* Update the connection counters */
120 - if (cp->cport || (cp->flags & IP_VS_CONN_F_NO_CPORT)) {
121 + if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
122 /* It is a normal connection, so increase the inactive
123 connection counter because it is in TCP SYNRECV
124 state (inactive) or other protocol inacive state */
125 @@ -406,7 +441,7 @@ static inline void ip_vs_unbind_dest(str
126 atomic_read(&dest->refcnt));
127
128 /* Update the connection counters */
129 - if (cp->cport || (cp->flags & IP_VS_CONN_F_NO_CPORT)) {
130 + if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
131 /* It is a normal connection, so decrease the inactconns
132 or activeconns counter */
133 if (cp->flags & IP_VS_CONN_F_INACTIVE) {
134 @@ -776,7 +811,7 @@ void ip_vs_random_dropentry(void)
135 ct_write_lock_bh(hash);
136
137 list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
138 - if (!cp->cport && !(cp->flags & IP_VS_CONN_F_NO_CPORT))
139 + if (cp->flags & IP_VS_CONN_F_TEMPLATE)
140 /* connection template */
141 continue;
142
143 Index: linux-2.6.13.y/net/ipv4/ipvs/ip_vs_core.c
144 ===================================================================
145 --- linux-2.6.13.y.orig/net/ipv4/ipvs/ip_vs_core.c
146 +++ linux-2.6.13.y/net/ipv4/ipvs/ip_vs_core.c
147 @@ -242,10 +242,10 @@ ip_vs_sched_persist(struct ip_vs_service
148 if (ports[1] == svc->port) {
149 /* Check if a template already exists */
150 if (svc->port != FTPPORT)
151 - ct = ip_vs_conn_in_get(iph->protocol, snet, 0,
152 + ct = ip_vs_ct_in_get(iph->protocol, snet, 0,
153 iph->daddr, ports[1]);
154 else
155 - ct = ip_vs_conn_in_get(iph->protocol, snet, 0,
156 + ct = ip_vs_ct_in_get(iph->protocol, snet, 0,
157 iph->daddr, 0);
158
159 if (!ct || !ip_vs_check_template(ct)) {
160 @@ -271,14 +271,14 @@ ip_vs_sched_persist(struct ip_vs_service
161 iph->daddr,
162 ports[1],
163 dest->addr, dest->port,
164 - 0,
165 + IP_VS_CONN_F_TEMPLATE,
166 dest);
167 else
168 ct = ip_vs_conn_new(iph->protocol,
169 snet, 0,
170 iph->daddr, 0,
171 dest->addr, 0,
172 - 0,
173 + IP_VS_CONN_F_TEMPLATE,
174 dest);
175 if (ct == NULL)
176 return NULL;
177 @@ -297,10 +297,10 @@ ip_vs_sched_persist(struct ip_vs_service
178 * port zero template: <protocol,caddr,0,vaddr,0,daddr,0>
179 */
180 if (svc->fwmark)
181 - ct = ip_vs_conn_in_get(IPPROTO_IP, snet, 0,
182 + ct = ip_vs_ct_in_get(IPPROTO_IP, snet, 0,
183 htonl(svc->fwmark), 0);
184 else
185 - ct = ip_vs_conn_in_get(iph->protocol, snet, 0,
186 + ct = ip_vs_ct_in_get(iph->protocol, snet, 0,
187 iph->daddr, 0);
188
189 if (!ct || !ip_vs_check_template(ct)) {
190 @@ -325,14 +325,14 @@ ip_vs_sched_persist(struct ip_vs_service
191 snet, 0,
192 htonl(svc->fwmark), 0,
193 dest->addr, 0,
194 - 0,
195 + IP_VS_CONN_F_TEMPLATE,
196 dest);
197 else
198 ct = ip_vs_conn_new(iph->protocol,
199 snet, 0,
200 iph->daddr, 0,
201 dest->addr, 0,
202 - 0,
203 + IP_VS_CONN_F_TEMPLATE,
204 dest);
205 if (ct == NULL)
206 return NULL;
207 Index: linux-2.6.13.y/net/ipv4/ipvs/ip_vs_sync.c
208 ===================================================================
209 --- linux-2.6.13.y.orig/net/ipv4/ipvs/ip_vs_sync.c
210 +++ linux-2.6.13.y/net/ipv4/ipvs/ip_vs_sync.c
211 @@ -297,16 +297,24 @@ static void ip_vs_process_message(const
212
213 p = (char *)buffer + sizeof(struct ip_vs_sync_mesg);
214 for (i=0; i<m->nr_conns; i++) {
215 + unsigned flags;
216 +
217 s = (struct ip_vs_sync_conn *)p;
218 - cp = ip_vs_conn_in_get(s->protocol,
219 - s->caddr, s->cport,
220 - s->vaddr, s->vport);
221 + flags = ntohs(s->flags);
222 + if (!(flags & IP_VS_CONN_F_TEMPLATE))
223 + cp = ip_vs_conn_in_get(s->protocol,
224 + s->caddr, s->cport,
225 + s->vaddr, s->vport);
226 + else
227 + cp = ip_vs_ct_in_get(s->protocol,
228 + s->caddr, s->cport,
229 + s->vaddr, s->vport);
230 if (!cp) {
231 cp = ip_vs_conn_new(s->protocol,
232 s->caddr, s->cport,
233 s->vaddr, s->vport,
234 s->daddr, s->dport,
235 - ntohs(s->flags), NULL);
236 + flags, NULL);
237 if (!cp) {
238 IP_VS_ERR("ip_vs_conn_new failed\n");
239 return;
240 @@ -315,11 +323,11 @@ static void ip_vs_process_message(const
241 } else if (!cp->dest) {
242 /* it is an entry created by the synchronization */
243 cp->state = ntohs(s->state);
244 - cp->flags = ntohs(s->flags) | IP_VS_CONN_F_HASHED;
245 + cp->flags = flags | IP_VS_CONN_F_HASHED;
246 } /* Note that we don't touch its state and flags
247 if it is a normal entry. */
248
249 - if (ntohs(s->flags) & IP_VS_CONN_F_SEQ_MASK) {
250 + if (flags & IP_VS_CONN_F_SEQ_MASK) {
251 opt = (struct ip_vs_sync_conn_options *)&s[1];
252 memcpy(&cp->in_seq, opt, sizeof(*opt));
253 p += FULL_CONN_SIZE;

  ViewVC Help
Powered by ViewVC 1.1.20