1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include <linux/module.h>
22#include <linux/kernel.h>
23#include <linux/skbuff.h>
24#include <linux/in.h>
25#include <linux/ip.h>
26#include <linux/netfilter.h>
27#include <net/net_namespace.h>
28#include <net/protocol.h>
29#include <net/tcp.h>
30#include <asm/system.h>
31#include <linux/stat.h>
32#include <linux/proc_fs.h>
33#include <linux/seq_file.h>
34#include <linux/mutex.h>
35
36#include <net/ip_vs.h>
37
38EXPORT_SYMBOL(register_ip_vs_app);
39EXPORT_SYMBOL(unregister_ip_vs_app);
40EXPORT_SYMBOL(register_ip_vs_app_inc);
41
42
43static LIST_HEAD(ip_vs_app_list);
44static DEFINE_MUTEX(__ip_vs_app_mutex);
45
46
47
48
49
50static inline int ip_vs_app_get(struct ip_vs_app *app)
51{
52 return try_module_get(app->module);
53}
54
55
56static inline void ip_vs_app_put(struct ip_vs_app *app)
57{
58 module_put(app->module);
59}
60
61
62
63
64
65static int
66ip_vs_app_inc_new(struct ip_vs_app *app, __u16 proto, __u16 port)
67{
68 struct ip_vs_protocol *pp;
69 struct ip_vs_app *inc;
70 int ret;
71
72 if (!(pp = ip_vs_proto_get(proto)))
73 return -EPROTONOSUPPORT;
74
75 if (!pp->unregister_app)
76 return -EOPNOTSUPP;
77
78 inc = kmemdup(app, sizeof(*inc), GFP_KERNEL);
79 if (!inc)
80 return -ENOMEM;
81 INIT_LIST_HEAD(&inc->p_list);
82 INIT_LIST_HEAD(&inc->incs_list);
83 inc->app = app;
84 inc->port = htons(port);
85 atomic_set(&inc->usecnt, 0);
86
87 if (app->timeouts) {
88 inc->timeout_table =
89 ip_vs_create_timeout_table(app->timeouts,
90 app->timeouts_size);
91 if (!inc->timeout_table) {
92 ret = -ENOMEM;
93 goto out;
94 }
95 }
96
97 ret = pp->register_app(inc);
98 if (ret)
99 goto out;
100
101 list_add(&inc->a_list, &app->incs_list);
102 IP_VS_DBG(9, "%s application %s:%u registered\n",
103 pp->name, inc->name, inc->port);
104
105 return 0;
106
107 out:
108 kfree(inc->timeout_table);
109 kfree(inc);
110 return ret;
111}
112
113
114
115
116
117static void
118ip_vs_app_inc_release(struct ip_vs_app *inc)
119{
120 struct ip_vs_protocol *pp;
121
122 if (!(pp = ip_vs_proto_get(inc->protocol)))
123 return;
124
125 if (pp->unregister_app)
126 pp->unregister_app(inc);
127
128 IP_VS_DBG(9, "%s App %s:%u unregistered\n",
129 pp->name, inc->name, inc->port);
130
131 list_del(&inc->a_list);
132
133 kfree(inc->timeout_table);
134 kfree(inc);
135}
136
137
138
139
140
141
142int ip_vs_app_inc_get(struct ip_vs_app *inc)
143{
144 int result;
145
146 atomic_inc(&inc->usecnt);
147 if (unlikely((result = ip_vs_app_get(inc->app)) != 1))
148 atomic_dec(&inc->usecnt);
149 return result;
150}
151
152
153
154
155
156void ip_vs_app_inc_put(struct ip_vs_app *inc)
157{
158 ip_vs_app_put(inc->app);
159 atomic_dec(&inc->usecnt);
160}
161
162
163
164
165
166int
167register_ip_vs_app_inc(struct ip_vs_app *app, __u16 proto, __u16 port)
168{
169 int result;
170
171 mutex_lock(&__ip_vs_app_mutex);
172
173 result = ip_vs_app_inc_new(app, proto, port);
174
175 mutex_unlock(&__ip_vs_app_mutex);
176
177 return result;
178}
179
180
181
182
183
184int register_ip_vs_app(struct ip_vs_app *app)
185{
186
187 ip_vs_use_count_inc();
188
189 mutex_lock(&__ip_vs_app_mutex);
190
191 list_add(&app->a_list, &ip_vs_app_list);
192
193 mutex_unlock(&__ip_vs_app_mutex);
194
195 return 0;
196}
197
198
199
200
201
202
203void unregister_ip_vs_app(struct ip_vs_app *app)
204{
205 struct ip_vs_app *inc, *nxt;
206
207 mutex_lock(&__ip_vs_app_mutex);
208
209 list_for_each_entry_safe(inc, nxt, &app->incs_list, a_list) {
210 ip_vs_app_inc_release(inc);
211 }
212
213 list_del(&app->a_list);
214
215 mutex_unlock(&__ip_vs_app_mutex);
216
217
218 ip_vs_use_count_dec();
219}
220
221
222
223
224
225int ip_vs_bind_app(struct ip_vs_conn *cp, struct ip_vs_protocol *pp)
226{
227 return pp->app_conn_bind(cp);
228}
229
230
231
232
233
234void ip_vs_unbind_app(struct ip_vs_conn *cp)
235{
236 struct ip_vs_app *inc = cp->app;
237
238 if (!inc)
239 return;
240
241 if (inc->unbind_conn)
242 inc->unbind_conn(inc, cp);
243 if (inc->done_conn)
244 inc->done_conn(inc, cp);
245 ip_vs_app_inc_put(inc);
246 cp->app = NULL;
247}
248
249
250
251
252
253static inline void vs_fix_seq(const struct ip_vs_seq *vseq, struct tcphdr *th)
254{
255 __u32 seq = ntohl(th->seq);
256
257
258
259
260
261
262 if (vseq->delta || vseq->previous_delta) {
263 if(after(seq, vseq->init_seq)) {
264 th->seq = htonl(seq + vseq->delta);
265 IP_VS_DBG(9, "vs_fix_seq(): added delta (%d) to seq\n",
266 vseq->delta);
267 } else {
268 th->seq = htonl(seq + vseq->previous_delta);
269 IP_VS_DBG(9, "vs_fix_seq(): added previous_delta "
270 "(%d) to seq\n", vseq->previous_delta);
271 }
272 }
273}
274
275
276
277
278
279static inline void
280vs_fix_ack_seq(const struct ip_vs_seq *vseq, struct tcphdr *th)
281{
282 __u32 ack_seq = ntohl(th->ack_seq);
283
284
285
286
287
288
289 if (vseq->delta || vseq->previous_delta) {
290
291
292 if(after(ack_seq, vseq->init_seq+vseq->delta)) {
293 th->ack_seq = htonl(ack_seq - vseq->delta);
294 IP_VS_DBG(9, "vs_fix_ack_seq(): subtracted delta "
295 "(%d) from ack_seq\n", vseq->delta);
296
297 } else {
298 th->ack_seq = htonl(ack_seq - vseq->previous_delta);
299 IP_VS_DBG(9, "vs_fix_ack_seq(): subtracted "
300 "previous_delta (%d) from ack_seq\n",
301 vseq->previous_delta);
302 }
303 }
304}
305
306
307
308
309
310
311static inline void vs_seq_update(struct ip_vs_conn *cp, struct ip_vs_seq *vseq,
312 unsigned flag, __u32 seq, int diff)
313{
314
315 spin_lock(&cp->lock);
316 if (!(cp->flags & flag) || after(seq, vseq->init_seq)) {
317 vseq->previous_delta = vseq->delta;
318 vseq->delta += diff;
319 vseq->init_seq = seq;
320 cp->flags |= flag;
321 }
322 spin_unlock(&cp->lock);
323}
324
325static inline int app_tcp_pkt_out(struct ip_vs_conn *cp, struct sk_buff *skb,
326 struct ip_vs_app *app)
327{
328 int diff;
329 const unsigned int tcp_offset = ip_hdrlen(skb);
330 struct tcphdr *th;
331 __u32 seq;
332
333 if (!skb_make_writable(skb, tcp_offset + sizeof(*th)))
334 return 0;
335
336 th = (struct tcphdr *)(skb_network_header(skb) + tcp_offset);
337
338
339
340
341 seq = ntohl(th->seq);
342
343
344
345
346 if (cp->flags & IP_VS_CONN_F_OUT_SEQ)
347 vs_fix_seq(&cp->out_seq, th);
348 if (cp->flags & IP_VS_CONN_F_IN_SEQ)
349 vs_fix_ack_seq(&cp->in_seq, th);
350
351
352
353
354 if (app->pkt_out == NULL)
355 return 1;
356
357 if (!app->pkt_out(app, cp, skb, &diff))
358 return 0;
359
360
361
362
363 if (diff != 0)
364 vs_seq_update(cp, &cp->out_seq,
365 IP_VS_CONN_F_OUT_SEQ, seq, diff);
366
367 return 1;
368}
369
370
371
372
373
374
375int ip_vs_app_pkt_out(struct ip_vs_conn *cp, struct sk_buff *skb)
376{
377 struct ip_vs_app *app;
378
379
380
381
382
383 if ((app = cp->app) == NULL)
384 return 1;
385
386
387 if (cp->protocol == IPPROTO_TCP)
388 return app_tcp_pkt_out(cp, skb, app);
389
390
391
392
393 if (app->pkt_out == NULL)
394 return 1;
395
396 return app->pkt_out(app, cp, skb, NULL);
397}
398
399
400static inline int app_tcp_pkt_in(struct ip_vs_conn *cp, struct sk_buff *skb,
401 struct ip_vs_app *app)
402{
403 int diff;
404 const unsigned int tcp_offset = ip_hdrlen(skb);
405 struct tcphdr *th;
406 __u32 seq;
407
408 if (!skb_make_writable(skb, tcp_offset + sizeof(*th)))
409 return 0;
410
411 th = (struct tcphdr *)(skb_network_header(skb) + tcp_offset);
412
413
414
415
416 seq = ntohl(th->seq);
417
418
419
420
421 if (cp->flags & IP_VS_CONN_F_IN_SEQ)
422 vs_fix_seq(&cp->in_seq, th);
423 if (cp->flags & IP_VS_CONN_F_OUT_SEQ)
424 vs_fix_ack_seq(&cp->out_seq, th);
425
426
427
428
429 if (app->pkt_in == NULL)
430 return 1;
431
432 if (!app->pkt_in(app, cp, skb, &diff))
433 return 0;
434
435
436
437
438 if (diff != 0)
439 vs_seq_update(cp, &cp->in_seq,
440 IP_VS_CONN_F_IN_SEQ, seq, diff);
441
442 return 1;
443}
444
445
446
447
448
449
450int ip_vs_app_pkt_in(struct ip_vs_conn *cp, struct sk_buff *skb)
451{
452 struct ip_vs_app *app;
453
454
455
456
457
458 if ((app = cp->app) == NULL)
459 return 1;
460
461
462 if (cp->protocol == IPPROTO_TCP)
463 return app_tcp_pkt_in(cp, skb, app);
464
465
466
467
468 if (app->pkt_in == NULL)
469 return 1;
470
471 return app->pkt_in(app, cp, skb, NULL);
472}
473
474
475#ifdef CONFIG_PROC_FS
476
477
478
479
480static struct ip_vs_app *ip_vs_app_idx(loff_t pos)
481{
482 struct ip_vs_app *app, *inc;
483
484 list_for_each_entry(app, &ip_vs_app_list, a_list) {
485 list_for_each_entry(inc, &app->incs_list, a_list) {
486 if (pos-- == 0)
487 return inc;
488 }
489 }
490 return NULL;
491
492}
493
494static void *ip_vs_app_seq_start(struct seq_file *seq, loff_t *pos)
495{
496 mutex_lock(&__ip_vs_app_mutex);
497
498 return *pos ? ip_vs_app_idx(*pos - 1) : SEQ_START_TOKEN;
499}
500
501static void *ip_vs_app_seq_next(struct seq_file *seq, void *v, loff_t *pos)
502{
503 struct ip_vs_app *inc, *app;
504 struct list_head *e;
505
506 ++*pos;
507 if (v == SEQ_START_TOKEN)
508 return ip_vs_app_idx(0);
509
510 inc = v;
511 app = inc->app;
512
513 if ((e = inc->a_list.next) != &app->incs_list)
514 return list_entry(e, struct ip_vs_app, a_list);
515
516
517 for (e = app->a_list.next; e != &ip_vs_app_list; e = e->next) {
518 app = list_entry(e, struct ip_vs_app, a_list);
519 list_for_each_entry(inc, &app->incs_list, a_list) {
520 return inc;
521 }
522 }
523 return NULL;
524}
525
526static void ip_vs_app_seq_stop(struct seq_file *seq, void *v)
527{
528 mutex_unlock(&__ip_vs_app_mutex);
529}
530
531static int ip_vs_app_seq_show(struct seq_file *seq, void *v)
532{
533 if (v == SEQ_START_TOKEN)
534 seq_puts(seq, "prot port usecnt name\n");
535 else {
536 const struct ip_vs_app *inc = v;
537
538 seq_printf(seq, "%-3s %-7u %-6d %-17s\n",
539 ip_vs_proto_name(inc->protocol),
540 ntohs(inc->port),
541 atomic_read(&inc->usecnt),
542 inc->name);
543 }
544 return 0;
545}
546
547static const struct seq_operations ip_vs_app_seq_ops = {
548 .start = ip_vs_app_seq_start,
549 .next = ip_vs_app_seq_next,
550 .stop = ip_vs_app_seq_stop,
551 .show = ip_vs_app_seq_show,
552};
553
554static int ip_vs_app_open(struct inode *inode, struct file *file)
555{
556 return seq_open(file, &ip_vs_app_seq_ops);
557}
558
559static const struct file_operations ip_vs_app_fops = {
560 .owner = THIS_MODULE,
561 .open = ip_vs_app_open,
562 .read = seq_read,
563 .llseek = seq_lseek,
564 .release = seq_release,
565};
566#endif
567
568
569
570
571
572int ip_vs_skb_replace(struct sk_buff *skb, gfp_t pri,
573 char *o_buf, int o_len, char *n_buf, int n_len)
574{
575 int diff;
576 int o_offset;
577 int o_left;
578
579 EnterFunction(9);
580
581 diff = n_len - o_len;
582 o_offset = o_buf - (char *)skb->data;
583
584 o_left = skb->len - (o_offset + o_len);
585
586 if (diff <= 0) {
587 memmove(o_buf + n_len, o_buf + o_len, o_left);
588 memcpy(o_buf, n_buf, n_len);
589 skb_trim(skb, skb->len + diff);
590 } else if (diff <= skb_tailroom(skb)) {
591 skb_put(skb, diff);
592 memmove(o_buf + n_len, o_buf + o_len, o_left);
593 memcpy(o_buf, n_buf, n_len);
594 } else {
595 if (pskb_expand_head(skb, skb_headroom(skb), diff, pri))
596 return -ENOMEM;
597 skb_put(skb, diff);
598 memmove(skb->data + o_offset + n_len,
599 skb->data + o_offset + o_len, o_left);
600 skb_copy_to_linear_data_offset(skb, o_offset, n_buf, n_len);
601 }
602
603
604 ip_hdr(skb)->tot_len = htons(skb->len);
605
606 LeaveFunction(9);
607 return 0;
608}
609
610
611int __init ip_vs_app_init(void)
612{
613
614 proc_net_fops_create(&init_net, "ip_vs_app", 0, &ip_vs_app_fops);
615 return 0;
616}
617
618
619void ip_vs_app_cleanup(void)
620{
621 proc_net_remove(&init_net, "ip_vs_app");
622}