1 /* 2 * ip_vs_ftp.c: IPVS ftp application module 3 * 4 * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> 5 * 6 * Changes: 7 * 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; either version 12 * 2 of the License, or (at your option) any later version. 13 * 14 * Most code here is taken from ip_masq_ftp.c in kernel 2.2. The difference 15 * is that ip_vs_ftp module handles the reverse direction to ip_masq_ftp. 16 * 17 * IP_MASQ_FTP ftp masquerading module 18 * 19 * Version: @(#)ip_masq_ftp.c 0.04 02/05/96 20 * 21 * Author: Wouter Gadeyne 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 54 enum { 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 * List of ports (up to IP_VS_APP_MAX_PORTS) to be handled by helper 64 * First port is set to the default port. 65 */ 66 static unsigned int ports_count = 1; 67 static unsigned short ports[IP_VS_APP_MAX_PORTS] = {21, 0}; 68 module_param_array(ports, ushort, &ports_count, 0444); 69 MODULE_PARM_DESC(ports, "Ports to monitor for FTP control commands"); 70 71 72 static 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 82 static int 83 ip_vs_ftp_init_conn(struct ip_vs_app *app, struct ip_vs_conn *cp) 84 { 85 /* We use connection tracking for the command connection */ 86 cp->flags |= IP_VS_CONN_F_NFCT; 87 return 0; 88 } 89 90 91 static int 92 ip_vs_ftp_done_conn(struct ip_vs_app *app, struct ip_vs_conn *cp) 93 { 94 return 0; 95 } 96 97 98 /* Get <addr,port> from the string "xxx.xxx.xxx.xxx,ppp,ppp", started 99 * with the "pattern". <addr,port> is in network order. 100 * Parse extended format depending on ext. In this case addr can be pre-set. 101 */ 102 static 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 /* check if there is partial match */ 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 bool found = false; 128 129 for (;; s++) { 130 if (s == data_limit) 131 return -1; 132 if (!found) { 133 /* "(" is optional for non-extended format, 134 * so catch the start of IPv4 address 135 */ 136 if (!ext && isdigit(*s)) 137 break; 138 if (*s == skip) 139 found = true; 140 } else if (*s != skip) { 141 break; 142 } 143 } 144 } 145 /* Old IPv4-only format? */ 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 /* unexpected character or terminator */ 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 /* Address family is usually missing for EPSV response */ 182 if (mode != IP_VS_FTP_EPSV) 183 return -1; 184 s++; 185 if (s == data_limit) 186 return -1; 187 /* Then address should be missing too */ 188 if (*s != edelim) 189 return -1; 190 /* Caller can pre-set addr, if needed */ 191 s++; 192 } else { 193 const char *ep; 194 195 /* We allow address only from same family */ 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 /* Look at outgoing ftp packets to catch the response to a PASV/EPSV command 241 * from the server (inside-to-outside). 242 * When we see one, we build a connection entry with the client address, 243 * client port 0 (unknown at the moment), the server address and the 244 * server port. Mark the current connection entry as a control channel 245 * of the new entry. All this work is just to make the data connection 246 * can be scheduled to the right server later. 247 * 248 * The outgoing packet should be something like 249 * "227 Entering Passive Mode (xxx,xxx,xxx,xxx,ppp,ppp)". 250 * xxx,xxx,xxx,xxx is the server address, ppp,ppp is the server port number. 251 * The extended format for EPSV response provides usually only port: 252 * "229 Entering Extended Passive Mode (|||ppp|)" 253 */ 254 static 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]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */ 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 /* Only useful for established sessions */ 272 if (cp->state != IP_VS_TCP_S_ESTABLISHED) 273 return 1; 274 275 /* Linear packets are much easier to deal with. */ 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 /* Usually, data address is not specified but 304 * we support different address, so pre-set it. 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 /* Now update or create a connection entry for it */ 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 /* add its controller */ 345 ip_vs_control_add(n_cp, cp); 346 } 347 348 /* Replace the old passive address with the new one */ 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 /* Only port, client will use VIP for the data connection */ 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 /* If mangling fails this function will return 0 375 * which will cause the packet to be dropped. 376 * Mangling can only fail under memory pressure, 377 * hopefully it will succeed on the retransmitted 378 * packet. 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 /* csum is updated */ 391 ret = 1; 392 } 393 } 394 395 /* Not setting 'diff' is intentional, otherwise the sequence 396 * would be adjusted twice. 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 /* Look at incoming ftp packets to catch the PASV/PORT/EPRT/EPSV command 407 * (outside-to-inside). 408 * 409 * The incoming packet having the PORT command should be something like 410 * "PORT xxx,xxx,xxx,xxx,ppp,ppp\n". 411 * xxx,xxx,xxx,xxx is the client address, ppp,ppp is the client port number. 412 * In this case, we create a connection entry using the client address and 413 * port, so that the active ftp data connection from the server can reach 414 * the client. 415 * Extended format: 416 * "EPSV\r\n" when client requests server address from same family 417 * "EPSV 1\r\n" when client requests IPv4 server address 418 * "EPSV 2\r\n" when client requests IPv6 server address 419 * "EPSV ALL\r\n" - not supported 420 * EPRT with specified delimiter (ASCII 33..126), "|" by default: 421 * "EPRT |1|IPv4ADDR|PORT|\r\n" when client provides IPv4 addrport 422 * "EPRT |2|IPv6ADDR|PORT|\r\n" when client provides IPv6 addrport 423 */ 424 static 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 /* no diff required for incoming packets */ 435 *diff = 0; 436 437 /* Only useful for established sessions */ 438 if (cp->state != IP_VS_TCP_S_ESTABLISHED) 439 return 1; 440 441 /* Linear packets are much easier to deal with. */ 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 /* Passive mode on */ 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 /* EPSV or EPSV<space><net-prt> */ 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 /* Extended Passive mode on */ 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 * To support virtual FTP server, the scenerio is as follows: 492 * FTP client ----> Load Balancer ----> FTP server 493 * First detect the port number in the application data, 494 * then create a new connection entry for the coming data 495 * connection. 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 /* Now update or create a connection entry for it */ 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 /* Now update or create a connection entry for it */ 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 /* Passive mode off */ 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 /* add its controller */ 550 ip_vs_control_add(n_cp, cp); 551 } 552 } 553 554 /* 555 * Move tunnel to listen state 556 */ 557 ip_vs_tcp_conn_listen(n_cp); 558 ip_vs_conn_put(n_cp); 559 560 return 1; 561 } 562 563 564 static 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 * per netns ip_vs_ftp initialization 580 */ 581 static 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 605 err_unreg: 606 unregister_ip_vs_app(ipvs, &ip_vs_ftp); 607 return ret; 608 } 609 /* 610 * netns exit 611 */ 612 static 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 622 static struct pernet_operations ip_vs_ftp_ops = { 623 .init = __ip_vs_ftp_init, 624 .exit = __ip_vs_ftp_exit, 625 }; 626 627 static int __init ip_vs_ftp_init(void) 628 { 629 /* rcu_barrier() is called by netns on error */ 630 return register_pernet_subsys(&ip_vs_ftp_ops); 631 } 632 633 /* 634 * ip_vs_ftp finish. 635 */ 636 static void __exit ip_vs_ftp_exit(void) 637 { 638 unregister_pernet_subsys(&ip_vs_ftp_ops); 639 /* rcu_barrier() is called by netns */ 640 } 641 642 643 module_init(ip_vs_ftp_init); 644 module_exit(ip_vs_ftp_exit); 645 MODULE_LICENSE("GPL"); 646