1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#define KMSG_COMPONENT "IPVS"
26#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
27
28#include <linux/module.h>
29#include <linux/moduleparam.h>
30#include <linux/kernel.h>
31#include <linux/skbuff.h>
32#include <linux/ctype.h>
33#include <linux/inet.h>
34#include <linux/in.h>
35#include <linux/ip.h>
36#include <linux/netfilter.h>
37#include <net/netfilter/nf_conntrack.h>
38#include <net/netfilter/nf_conntrack_expect.h>
39#include <net/netfilter/nf_nat.h>
40#include <net/netfilter/nf_nat_helper.h>
41#include <linux/gfp.h>
42#include <net/protocol.h>
43#include <net/tcp.h>
44#include <asm/unaligned.h>
45
46#include <net/ip_vs.h>
47
48
49#define SERVER_STRING_PASV "227 "
50#define CLIENT_STRING_PORT "PORT"
51#define SERVER_STRING_EPSV "229 "
52#define CLIENT_STRING_EPRT "EPRT"
53
54enum {
55 IP_VS_FTP_ACTIVE = 0,
56 IP_VS_FTP_PORT = 0,
57 IP_VS_FTP_PASV,
58 IP_VS_FTP_EPRT,
59 IP_VS_FTP_EPSV,
60};
61
62
63
64
65
66static unsigned int ports_count = 1;
67static unsigned short ports[IP_VS_APP_MAX_PORTS] = {21, 0};
68module_param_array(ports, ushort, &ports_count, 0444);
69MODULE_PARM_DESC(ports, "Ports to monitor for FTP control commands");
70
71
72static char *ip_vs_ftp_data_ptr(struct sk_buff *skb, struct ip_vs_iphdr *ipvsh)
73{
74 struct tcphdr *th = (struct tcphdr *)((char *)skb->data + ipvsh->len);
75
76 if ((th->doff << 2) < sizeof(struct tcphdr))
77 return NULL;
78
79 return (char *)th + (th->doff << 2);
80}
81
82static int
83ip_vs_ftp_init_conn(struct ip_vs_app *app, struct ip_vs_conn *cp)
84{
85
86 cp->flags |= IP_VS_CONN_F_NFCT;
87 return 0;
88}
89
90
91static int
92ip_vs_ftp_done_conn(struct ip_vs_app *app, struct ip_vs_conn *cp)
93{
94 return 0;
95}
96
97
98
99
100
101
102static int ip_vs_ftp_get_addrport(char *data, char *data_limit,
103 const char *pattern, size_t plen,
104 char skip, bool ext, int mode,
105 union nf_inet_addr *addr, __be16 *port,
106 __u16 af, char **start, char **end)
107{
108 char *s, c;
109 unsigned char p[6];
110 char edelim;
111 __u16 hport;
112 int i = 0;
113
114 if (data_limit - data < plen) {
115
116 if (strncasecmp(data, pattern, data_limit - data) == 0)
117 return -1;
118 else
119 return 0;
120 }
121
122 if (strncasecmp(data, pattern, plen) != 0) {
123 return 0;
124 }
125 s = data + plen;
126 if (skip) {
127 int found = 0;
128
129 for (;; s++) {
130 if (s == data_limit)
131 return -1;
132 if (!found) {
133
134
135
136 if (!ext && isdigit(*s))
137 break;
138 if (*s == skip)
139 found = 1;
140 } else if (*s != skip) {
141 break;
142 }
143 }
144 }
145
146 if (!ext) {
147 p[0] = 0;
148 for (data = s; ; data++) {
149 if (data == data_limit)
150 return -1;
151 c = *data;
152 if (isdigit(c)) {
153 p[i] = p[i]*10 + c - '0';
154 } else if (c == ',' && i < 5) {
155 i++;
156 p[i] = 0;
157 } else {
158
159 break;
160 }
161 }
162
163 if (i != 5)
164 return -1;
165
166 *start = s;
167 *end = data;
168 addr->ip = get_unaligned((__be32 *) p);
169 *port = get_unaligned((__be16 *) (p + 4));
170 return 1;
171 }
172 if (s == data_limit)
173 return -1;
174 *start = s;
175 edelim = *s++;
176 if (edelim < 33 || edelim > 126)
177 return -1;
178 if (s == data_limit)
179 return -1;
180 if (*s == edelim) {
181
182 if (mode != IP_VS_FTP_EPSV)
183 return -1;
184 s++;
185 if (s == data_limit)
186 return -1;
187
188 if (*s != edelim)
189 return -1;
190
191 s++;
192 } else {
193 const char *ep;
194
195
196 if (af == AF_INET6 && *s != '2')
197 return -1;
198 if (af == AF_INET && *s != '1')
199 return -1;
200 s++;
201 if (s == data_limit)
202 return -1;
203 if (*s != edelim)
204 return -1;
205 s++;
206 if (s == data_limit)
207 return -1;
208 if (af == AF_INET6) {
209 if (in6_pton(s, data_limit - s, (u8 *)addr, edelim,
210 &ep) <= 0)
211 return -1;
212 } else {
213 if (in4_pton(s, data_limit - s, (u8 *)addr, edelim,
214 &ep) <= 0)
215 return -1;
216 }
217 s = (char *) ep;
218 if (s == data_limit)
219 return -1;
220 if (*s != edelim)
221 return -1;
222 s++;
223 }
224 for (hport = 0; ; s++)
225 {
226 if (s == data_limit)
227 return -1;
228 if (!isdigit(*s))
229 break;
230 hport = hport * 10 + *s - '0';
231 }
232 if (s == data_limit || !hport || *s != edelim)
233 return -1;
234 s++;
235 *end = s;
236 *port = htons(hport);
237 return 1;
238}
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
255 struct sk_buff *skb, int *diff,
256 struct ip_vs_iphdr *ipvsh)
257{
258 char *data, *data_limit;
259 char *start, *end;
260 union nf_inet_addr from;
261 __be16 port;
262 struct ip_vs_conn *n_cp;
263 char buf[24];
264 unsigned int buf_len;
265 int ret = 0;
266 enum ip_conntrack_info ctinfo;
267 struct nf_conn *ct;
268
269 *diff = 0;
270
271
272 if (cp->state != IP_VS_TCP_S_ESTABLISHED)
273 return 1;
274
275
276 if (!skb_make_writable(skb, skb->len))
277 return 0;
278
279 if (cp->app_data == (void *) IP_VS_FTP_PASV) {
280 data = ip_vs_ftp_data_ptr(skb, ipvsh);
281 data_limit = skb_tail_pointer(skb);
282
283 if (!data || data >= data_limit)
284 return 1;
285
286 if (ip_vs_ftp_get_addrport(data, data_limit,
287 SERVER_STRING_PASV,
288 sizeof(SERVER_STRING_PASV)-1,
289 '(', false, IP_VS_FTP_PASV,
290 &from, &port, cp->af,
291 &start, &end) != 1)
292 return 1;
293
294 IP_VS_DBG(7, "PASV response (%pI4:%u) -> %pI4:%u detected\n",
295 &from.ip, ntohs(port), &cp->caddr.ip, 0);
296 } else if (cp->app_data == (void *) IP_VS_FTP_EPSV) {
297 data = ip_vs_ftp_data_ptr(skb, ipvsh);
298 data_limit = skb_tail_pointer(skb);
299
300 if (!data || data >= data_limit)
301 return 1;
302
303
304
305
306 from = cp->daddr;
307 if (ip_vs_ftp_get_addrport(data, data_limit,
308 SERVER_STRING_EPSV,
309 sizeof(SERVER_STRING_EPSV)-1,
310 '(', true, IP_VS_FTP_EPSV,
311 &from, &port, cp->af,
312 &start, &end) != 1)
313 return 1;
314
315 IP_VS_DBG_BUF(7, "EPSV response (%s:%u) -> %s:%u detected\n",
316 IP_VS_DBG_ADDR(cp->af, &from), ntohs(port),
317 IP_VS_DBG_ADDR(cp->af, &cp->caddr), 0);
318 } else {
319 return 1;
320 }
321
322
323 {
324 struct ip_vs_conn_param p;
325
326 ip_vs_conn_fill_param(cp->ipvs, cp->af,
327 ipvsh->protocol, &from, port,
328 &cp->caddr, 0, &p);
329 n_cp = ip_vs_conn_out_get(&p);
330 }
331 if (!n_cp) {
332 struct ip_vs_conn_param p;
333
334 ip_vs_conn_fill_param(cp->ipvs,
335 cp->af, ipvsh->protocol, &cp->caddr,
336 0, &cp->vaddr, port, &p);
337 n_cp = ip_vs_conn_new(&p, cp->af, &from, port,
338 IP_VS_CONN_F_NO_CPORT |
339 IP_VS_CONN_F_NFCT,
340 cp->dest, skb->mark);
341 if (!n_cp)
342 return 0;
343
344
345 ip_vs_control_add(n_cp, cp);
346 }
347
348
349 if (cp->app_data == (void *) IP_VS_FTP_PASV) {
350 from.ip = n_cp->vaddr.ip;
351 port = n_cp->vport;
352 snprintf(buf, sizeof(buf), "%u,%u,%u,%u,%u,%u",
353 ((unsigned char *)&from.ip)[0],
354 ((unsigned char *)&from.ip)[1],
355 ((unsigned char *)&from.ip)[2],
356 ((unsigned char *)&from.ip)[3],
357 ntohs(port) >> 8,
358 ntohs(port) & 0xFF);
359 } else if (cp->app_data == (void *) IP_VS_FTP_EPSV) {
360 from = n_cp->vaddr;
361 port = n_cp->vport;
362
363 snprintf(buf, sizeof(buf), "|||%u|",
364 ntohs(port));
365 } else {
366 *buf = 0;
367 }
368 buf_len = strlen(buf);
369
370 ct = nf_ct_get(skb, &ctinfo);
371 if (ct) {
372 bool mangled;
373
374
375
376
377
378
379
380 mangled = nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
381 ipvsh->len,
382 start - data,
383 end - start,
384 buf, buf_len);
385 if (mangled) {
386 ip_vs_nfct_expect_related(skb, ct, n_cp,
387 ipvsh->protocol, 0, 0);
388 if (skb->ip_summed == CHECKSUM_COMPLETE)
389 skb->ip_summed = CHECKSUM_UNNECESSARY;
390
391 ret = 1;
392 }
393 }
394
395
396
397
398
399 cp->app_data = (void *) IP_VS_FTP_ACTIVE;
400 ip_vs_tcp_conn_listen(n_cp);
401 ip_vs_conn_put(n_cp);
402 return ret;
403}
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
425 struct sk_buff *skb, int *diff,
426 struct ip_vs_iphdr *ipvsh)
427{
428 char *data, *data_start, *data_limit;
429 char *start, *end;
430 union nf_inet_addr to;
431 __be16 port;
432 struct ip_vs_conn *n_cp;
433
434
435 *diff = 0;
436
437
438 if (cp->state != IP_VS_TCP_S_ESTABLISHED)
439 return 1;
440
441
442 if (!skb_make_writable(skb, skb->len))
443 return 0;
444
445 data = data_start = ip_vs_ftp_data_ptr(skb, ipvsh);
446 data_limit = skb_tail_pointer(skb);
447 if (!data || data >= data_limit)
448 return 1;
449
450 while (data <= data_limit - 6) {
451 if (cp->af == AF_INET &&
452 strncasecmp(data, "PASV\r\n", 6) == 0) {
453
454 IP_VS_DBG(7, "got PASV at %td of %td\n",
455 data - data_start,
456 data_limit - data_start);
457 cp->app_data = (void *) IP_VS_FTP_PASV;
458 return 1;
459 }
460
461
462 if (strncasecmp(data, "EPSV", 4) == 0 &&
463 (data[4] == ' ' || data[4] == '\r')) {
464 if (data[4] == ' ') {
465 char proto = data[5];
466
467 if (data > data_limit - 7 || data[6] != '\r')
468 return 1;
469
470#ifdef CONFIG_IP_VS_IPV6
471 if (cp->af == AF_INET6 && proto == '2') {
472 } else
473#endif
474 if (cp->af == AF_INET && proto == '1') {
475 } else {
476 return 1;
477 }
478 }
479
480 IP_VS_DBG(7, "got EPSV at %td of %td\n",
481 data - data_start,
482 data_limit - data_start);
483 cp->app_data = (void *) IP_VS_FTP_EPSV;
484 return 1;
485 }
486
487 data++;
488 }
489
490
491
492
493
494
495
496
497 if (cp->af == AF_INET &&
498 ip_vs_ftp_get_addrport(data_start, data_limit,
499 CLIENT_STRING_PORT,
500 sizeof(CLIENT_STRING_PORT)-1,
501 ' ', false, IP_VS_FTP_PORT,
502 &to, &port, cp->af,
503 &start, &end) == 1) {
504
505 IP_VS_DBG(7, "PORT %pI4:%u detected\n", &to.ip, ntohs(port));
506
507
508 IP_VS_DBG(7, "protocol %s %pI4:%u %pI4:%u\n",
509 ip_vs_proto_name(ipvsh->protocol),
510 &to.ip, ntohs(port), &cp->vaddr.ip,
511 ntohs(cp->vport)-1);
512 } else if (ip_vs_ftp_get_addrport(data_start, data_limit,
513 CLIENT_STRING_EPRT,
514 sizeof(CLIENT_STRING_EPRT)-1,
515 ' ', true, IP_VS_FTP_EPRT,
516 &to, &port, cp->af,
517 &start, &end) == 1) {
518
519 IP_VS_DBG_BUF(7, "EPRT %s:%u detected\n",
520 IP_VS_DBG_ADDR(cp->af, &to), ntohs(port));
521
522
523 IP_VS_DBG_BUF(7, "protocol %s %s:%u %s:%u\n",
524 ip_vs_proto_name(ipvsh->protocol),
525 IP_VS_DBG_ADDR(cp->af, &to), ntohs(port),
526 IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
527 ntohs(cp->vport)-1);
528 } else {
529 return 1;
530 }
531
532
533 cp->app_data = (void *) IP_VS_FTP_ACTIVE;
534
535 {
536 struct ip_vs_conn_param p;
537 ip_vs_conn_fill_param(cp->ipvs, cp->af,
538 ipvsh->protocol, &to, port, &cp->vaddr,
539 htons(ntohs(cp->vport)-1), &p);
540 n_cp = ip_vs_conn_in_get(&p);
541 if (!n_cp) {
542 n_cp = ip_vs_conn_new(&p, cp->af, &cp->daddr,
543 htons(ntohs(cp->dport)-1),
544 IP_VS_CONN_F_NFCT, cp->dest,
545 skb->mark);
546 if (!n_cp)
547 return 0;
548
549
550 ip_vs_control_add(n_cp, cp);
551 }
552 }
553
554
555
556
557 ip_vs_tcp_conn_listen(n_cp);
558 ip_vs_conn_put(n_cp);
559
560 return 1;
561}
562
563
564static struct ip_vs_app ip_vs_ftp = {
565 .name = "ftp",
566 .type = IP_VS_APP_TYPE_FTP,
567 .protocol = IPPROTO_TCP,
568 .module = THIS_MODULE,
569 .incs_list = LIST_HEAD_INIT(ip_vs_ftp.incs_list),
570 .init_conn = ip_vs_ftp_init_conn,
571 .done_conn = ip_vs_ftp_done_conn,
572 .bind_conn = NULL,
573 .unbind_conn = NULL,
574 .pkt_out = ip_vs_ftp_out,
575 .pkt_in = ip_vs_ftp_in,
576};
577
578
579
580
581static int __net_init __ip_vs_ftp_init(struct net *net)
582{
583 int i, ret;
584 struct ip_vs_app *app;
585 struct netns_ipvs *ipvs = net_ipvs(net);
586
587 if (!ipvs)
588 return -ENOENT;
589
590 app = register_ip_vs_app(ipvs, &ip_vs_ftp);
591 if (IS_ERR(app))
592 return PTR_ERR(app);
593
594 for (i = 0; i < ports_count; i++) {
595 if (!ports[i])
596 continue;
597 ret = register_ip_vs_app_inc(ipvs, app, app->protocol, ports[i]);
598 if (ret)
599 goto err_unreg;
600 pr_info("%s: loaded support on port[%d] = %u\n",
601 app->name, i, ports[i]);
602 }
603 return 0;
604
605err_unreg:
606 unregister_ip_vs_app(ipvs, &ip_vs_ftp);
607 return ret;
608}
609
610
611
612static void __ip_vs_ftp_exit(struct net *net)
613{
614 struct netns_ipvs *ipvs = net_ipvs(net);
615
616 if (!ipvs)
617 return;
618
619 unregister_ip_vs_app(ipvs, &ip_vs_ftp);
620}
621
622static struct pernet_operations ip_vs_ftp_ops = {
623 .init = __ip_vs_ftp_init,
624 .exit = __ip_vs_ftp_exit,
625};
626
627static int __init ip_vs_ftp_init(void)
628{
629
630 return register_pernet_subsys(&ip_vs_ftp_ops);
631}
632
633
634
635
636static void __exit ip_vs_ftp_exit(void)
637{
638 unregister_pernet_subsys(&ip_vs_ftp_ops);
639
640}
641
642
643module_init(ip_vs_ftp_init);
644module_exit(ip_vs_ftp_exit);
645MODULE_LICENSE("GPL");
646