1 /* $OpenBSD: ftp-proxy.c,v 1.41 2005/03/05 23:11:19 cloder Exp $ */
4 * Copyright (c) 1996-2001
5 * Obtuse Systems Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the Obtuse Systems nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY OBTUSE SYSTEMS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL OBTUSE SYSTEMS CORPORATION OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
37 * ftp proxy, Originally based on juniper_ftp_proxy from the Obtuse
38 * Systems juniper firewall, written by Dan Boulet <danny@obtuse.com>
39 * and Bob Beck <beck@obtuse.com>
41 * This version basically passes everything through unchanged except
42 * for the PORT and the * "227 Entering Passive Mode" reply.
44 * A PORT command is handled by noting the IP address and port number
45 * specified and then configuring a listen port on some very high port
46 * number and telling the server about it using a PORT message.
47 * We then watch for an in-bound connection on the port from the server
48 * and connect to the client's port when it happens.
50 * A "227 Entering Passive Mode" reply is handled by noting the IP address
51 * and port number specified and then configuring a listen port on some
52 * very high port number and telling the client about it using a
53 * "227 Entering Passive Mode" reply.
54 * We then watch for an in-bound connection on the port from the client
55 * and connect to the server's port when it happens.
57 * supports tcp wrapper lookups/access control with the -w flag using
58 * the real destination address - the tcp wrapper stuff is done after
59 * the real destination address is retrieved from pf
65 * Plenty, this is very basic, with the idea to get it in clean first.
67 * - IPv6 and EPASV support
68 * - Content filter support
69 * - filename filter support
70 * - per-user rules perhaps.
73 #include <sys/param.h>
75 #include <sys/socket.h>
78 #include <netinet/in.h>
80 #include <arpa/inet.h>
100 int allow_severity = LOG_INFO;
101 int deny_severity = LOG_NOTICE;
104 int min_port = IPPORT_HIFIRSTAUTO;
105 int max_port = IPPORT_HILASTAUTO;
107 #define STARTBUFSIZE 1024 /* Must be at least 3 */
110 * Variables used to support PORT mode connections.
112 * This gets a bit complicated.
114 * If PORT mode is on then client_listen_sa describes the socket that
115 * the real client is listening on and server_listen_sa describes the
116 * socket that we are listening on (waiting for the real server to connect
119 * If PASV mode is on then client_listen_sa describes the socket that
120 * we are listening on (waiting for the real client to connect to us on)
121 * and server_listen_sa describes the socket that the real server is
124 * If the socket we are listening on gets a connection then we connect
125 * to the other side's socket. Similarly, if a connected socket is
126 * shutdown then we shutdown the other side's socket.
129 double xfer_start_time;
131 struct sockaddr_in real_server_sa;
132 struct sockaddr_in client_listen_sa;
133 struct sockaddr_in server_listen_sa;
134 struct sockaddr_in proxy_sa;
135 struct in_addr src_addr;
137 int client_listen_socket = -1; /* Only used in PASV mode */
138 int client_data_socket = -1; /* Connected socket to real client */
139 int server_listen_socket = -1; /* Only used in PORT mode */
140 int server_data_socket = -1; /* Connected socket to real server */
141 int client_data_bytes, server_data_bytes;
148 char ClientName[NI_MAXHOST];
149 char RealServerName[NI_MAXHOST];
150 char OurName[NI_MAXHOST];
152 const char *User = "proxy";
155 extern int Debug_Level;
157 extern in_addr_t Bind_Addr;
158 extern char *__progname;
168 connection_mode_t connection_mode;
170 extern void debuglog(int debug_level, const char *fmt, ...);
171 double wallclock_time(void);
172 void show_xfer_stats(void);
173 void log_control_command (char *cmd, int client);
174 int new_dataconn(int server);
175 void do_client_cmd(struct csiob *client, struct csiob *server);
176 void do_server_reply(struct csiob *server, struct csiob *client);
181 "usage: %s [-AnrVw] [-a address] [-D debuglevel] [-g group]"
182 " [-M maxport] [-m minport] [-R address[:port]] [-S address]"
183 " [-t timeout] [-u user]", __progname);
188 close_client_data(void)
190 if (client_data_socket >= 0) {
191 shutdown(client_data_socket, 2);
192 close(client_data_socket);
193 client_data_socket = -1;
198 close_server_data(void)
200 if (server_data_socket >= 0) {
201 shutdown(server_data_socket, 2);
202 close(server_data_socket);
203 server_data_socket = -1;
218 syslog(LOG_ERR, "cannot find user %s", User);
226 gr = getgrnam(Group);
228 syslog(LOG_ERR, "cannot find group %s", Group);
234 if (gid != 0 && (setegid(gid) == -1 || setgid(gid) == -1)) {
235 syslog(LOG_ERR, "cannot drop group privs (%m)");
239 if (uid != 0 && (seteuid(uid) == -1 || setuid(uid) == -1)) {
240 syslog(LOG_ERR, "cannot drop root privs (%m)");
247 * Check a connection against the tcpwrapper, log if we're going to
248 * reject it, returns: 0 -> reject, 1 -> accept. We add in hostnames
249 * if we are set to do reverse DNS, otherwise no.
252 check_host(struct sockaddr_in *client_sin, struct sockaddr_in *server_sin)
254 char cname[NI_MAXHOST];
255 char sname[NI_MAXHOST];
256 struct request_info request;
259 request_init(&request, RQ_DAEMON, __progname, RQ_CLIENT_SIN,
260 client_sin, RQ_SERVER_SIN, server_sin, RQ_CLIENT_ADDR,
261 inet_ntoa(client_sin->sin_addr), 0);
265 * We already looked these up, but we have to do it again
266 * for tcp wrapper, to ensure that we get the DNS name, since
267 * the tcp wrapper cares about these things, and we don't
268 * want to pass in a printed address as a name.
270 i = getnameinfo((struct sockaddr *) &client_sin->sin_addr,
271 sizeof(&client_sin->sin_addr), cname, sizeof(cname),
272 NULL, 0, NI_NAMEREQD);
274 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN)
275 strlcpy(cname, STRING_UNKNOWN, sizeof(cname));
277 i = getnameinfo((struct sockaddr *)&server_sin->sin_addr,
278 sizeof(&server_sin->sin_addr), sname, sizeof(sname),
279 NULL, 0, NI_NAMEREQD);
281 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN)
282 strlcpy(sname, STRING_UNKNOWN, sizeof(sname));
285 * ensure the TCP wrapper doesn't start doing
286 * reverse DNS lookups if we aren't supposed to.
288 strlcpy(cname, STRING_UNKNOWN, sizeof(cname));
289 strlcpy(sname, STRING_UNKNOWN, sizeof(sname));
292 request_set(&request, RQ_SERVER_ADDR, inet_ntoa(server_sin->sin_addr),
294 request_set(&request, RQ_CLIENT_NAME, cname, RQ_SERVER_NAME, sname, 0);
296 if (!hosts_access(&request)) {
297 syslog(LOG_NOTICE, "tcpwrappers rejected: %s -> %s",
298 ClientName, RealServerName);
310 gettimeofday(&tv, NULL);
311 return(tv.tv_sec + tv.tv_usec / 1e6);
315 * Show the stats for this data transfer
318 show_xfer_stats(void)
328 delta = wallclock_time() - xfer_start_time;
333 if (client_data_bytes == 0 && server_data_bytes == 0) {
335 "data transfer complete (no bytes transferred)");
344 idelta = delta + 0.5;
345 if (idelta >= 60*60) {
346 i = snprintf(tbuf, len,
347 "data transfer complete (%dh %dm %ds",
348 idelta / (60*60), (idelta % (60*60)) / 60,
350 if (i == -1 || i >= len)
354 i = snprintf(tbuf, len,
355 "data transfer complete (%dm %ds", idelta / 60,
357 if (i == -1 || i >= len)
362 i = snprintf(tbuf, len, "data transfer complete (%.1fs",
364 if (i == -1 || i >= len)
369 if (client_data_bytes > 0) {
370 i = snprintf(&tbuf[strlen(tbuf)], len,
371 ", %d bytes to server) (%.1fKB/s", client_data_bytes,
372 (client_data_bytes / delta) / (double)1024);
373 if (i == -1 || i >= len)
377 if (server_data_bytes > 0) {
378 i = snprintf(&tbuf[strlen(tbuf)], len,
379 ", %d bytes to client) (%.1fKB/s", server_data_bytes,
380 (server_data_bytes / delta) / (double)1024);
381 if (i == -1 || i >= len)
385 strlcat(tbuf, ")", sizeof(tbuf));
388 syslog(LOG_INFO, "%s", tbuf);
392 log_control_command (char *cmd, int client)
394 /* log an ftp control command or reply */
395 const char *logstring;
396 int level = LOG_DEBUG;
401 /* don't log passwords */
402 if (strncasecmp(cmd, "pass ", 5) == 0)
403 logstring = "PASS XXXX";
407 /* log interesting stuff at LOG_INFO, rest at LOG_DEBUG */
408 if ((strncasecmp(cmd, "user ", 5) == 0) ||
409 (strncasecmp(cmd, "retr ", 5) == 0) ||
410 (strncasecmp(cmd, "cwd ", 4) == 0) ||
411 (strncasecmp(cmd, "stor " ,5) == 0))
414 syslog(level, "%s %s", client ? "client:" : " server:",
419 * set ourselves up for a new data connection. Direction is toward client if
420 * "server" is 0, towards server otherwise.
423 new_dataconn(int server)
426 * Close existing data conn.
429 if (client_listen_socket != -1) {
430 close(client_listen_socket);
431 client_listen_socket = -1;
435 if (server_listen_socket != -1) {
436 close(server_listen_socket);
437 server_listen_socket = -1;
442 bzero(&server_listen_sa, sizeof(server_listen_sa));
443 server_listen_socket = get_backchannel_socket(SOCK_STREAM,
444 min_port, max_port, -1, 1, &server_listen_sa);
446 if (server_listen_socket == -1) {
447 syslog(LOG_INFO, "server socket bind() failed (%m)");
450 if (listen(server_listen_socket, 5) != 0) {
451 syslog(LOG_INFO, "server socket listen() failed (%m)");
455 bzero(&client_listen_sa, sizeof(client_listen_sa));
456 client_listen_socket = get_backchannel_socket(SOCK_STREAM,
457 min_port, max_port, -1, 1, &client_listen_sa);
459 if (client_listen_socket == -1) {
461 "cannot get client listen socket (%m)");
464 if (listen(client_listen_socket, 5) != 0) {
466 "cannot listen on client socket (%m)");
474 connect_pasv_backchannel(void)
476 struct sockaddr_in listen_sa;
480 * We are about to accept a connection from the client.
481 * This is a PASV data connection.
483 debuglog(2, "client listen socket ready");
488 salen = sizeof(listen_sa);
489 client_data_socket = accept(client_listen_socket,
490 (struct sockaddr *)&listen_sa, &salen);
492 if (client_data_socket < 0) {
493 syslog(LOG_NOTICE, "accept() failed (%m)");
496 close(client_listen_socket);
497 client_listen_socket = -1;
498 memset(&listen_sa, 0, sizeof(listen_sa));
500 server_data_socket = get_backchannel_socket(SOCK_STREAM, min_port,
501 max_port, -1, 1, &listen_sa);
502 if (server_data_socket < 0) {
503 syslog(LOG_NOTICE, "get_backchannel_socket() failed (%m)");
506 if (connect(server_data_socket, (struct sockaddr *) &server_listen_sa,
507 sizeof(server_listen_sa)) != 0) {
508 syslog(LOG_NOTICE, "connect() failed (%m)");
511 client_data_bytes = 0;
512 server_data_bytes = 0;
513 xfer_start_time = wallclock_time();
517 connect_port_backchannel(void)
519 struct sockaddr_in listen_sa;
523 * We are about to accept a connection from the server.
524 * This is a PORT or EPRT data connection.
526 debuglog(2, "server listen socket ready");
531 salen = sizeof(listen_sa);
532 server_data_socket = accept(server_listen_socket,
533 (struct sockaddr *)&listen_sa, &salen);
534 if (server_data_socket < 0) {
535 syslog(LOG_NOTICE, "accept() failed (%m)");
538 close(server_listen_socket);
539 server_listen_socket = -1;
543 * We're not running as root, so we get a backchannel
544 * socket bound in our designated range, instead of
545 * getting one bound to port 20 - This is deliberately
548 bcopy(&src_addr, &listen_sa.sin_addr, sizeof(struct in_addr));
549 client_data_socket = get_backchannel_socket(SOCK_STREAM,
550 min_port, max_port, -1, 1, &listen_sa);
551 if (client_data_socket < 0) {
552 syslog(LOG_NOTICE, "get_backchannel_socket() failed (%m)");
559 * We're root, get our backchannel socket bound to port
560 * 20 here, so we're fully RFC compliant.
562 client_data_socket = socket(AF_INET, SOCK_STREAM, 0);
565 listen_sa.sin_family = AF_INET;
566 bcopy(&src_addr, &listen_sa.sin_addr, sizeof(struct in_addr));
567 listen_sa.sin_port = htons(20);
569 if (setsockopt(client_data_socket, SOL_SOCKET, SO_REUSEADDR,
570 &salen, sizeof(salen)) == -1) {
571 syslog(LOG_NOTICE, "setsockopt() failed (%m)");
575 if (bind(client_data_socket, (struct sockaddr *)&listen_sa,
576 sizeof(listen_sa)) == - 1) {
577 syslog(LOG_NOTICE, "data channel bind() failed (%m)");
582 if (connect(client_data_socket, (struct sockaddr *) &client_listen_sa,
583 sizeof(client_listen_sa)) != 0) {
584 syslog(LOG_INFO, "cannot connect data channel (%m)");
588 client_data_bytes = 0;
589 server_data_bytes = 0;
590 xfer_start_time = wallclock_time();
594 do_client_cmd(struct csiob *client, struct csiob *server)
598 char *sendbuf = NULL;
600 log_control_command((char *)client->line_buffer, 1);
602 /* client->line_buffer is an ftp control command.
603 * There is no reason for these to be very long.
604 * In the interest of limiting buffer overrun attempts,
605 * we catch them here.
607 if (strlen((char *)client->line_buffer) > 512) {
608 syslog(LOG_NOTICE, "excessively long control command");
613 * Check the client user provided if needed
615 if (AnonFtpOnly && strncasecmp((char *)client->line_buffer, "user ",
616 strlen("user ")) == 0) {
619 cp = (char *) client->line_buffer + strlen("user ");
620 if ((strcasecmp(cp, "ftp\r\n") != 0) &&
621 (strcasecmp(cp, "anonymous\r\n") != 0)) {
623 * this isn't anonymous - give the client an
624 * error before they send a password
626 snprintf(tbuf, sizeof(tbuf),
627 "500 Only anonymous FTP is allowed\r\n");
631 rv = send(client->fd, tbuf + j, i - j, 0);
632 if (rv == -1 && errno != EAGAIN &&
637 } while (j >= 0 && j < i);
640 sendbuf = (char *)client->line_buffer;
641 } else if ((strncasecmp((char *)client->line_buffer, "eprt ",
642 strlen("eprt ")) == 0)) {
644 /* Watch out for EPRT commands */
645 char *line = NULL, *q, *p, *result[3], delim;
646 struct addrinfo hints, *res = NULL;
650 line = strdup((char *)client->line_buffer+strlen("eprt "));
652 syslog(LOG_ERR, "insufficient memory");
653 exit(EX_UNAVAILABLE);
659 memset(result,0, sizeof(result));
660 for (i = 0; i < 3; i++) {
661 q = strchr(p, delim);
662 if (!q || *q != delim)
669 proto = strtoul(result[0], &p, 10);
670 if (!*result[0] || *p)
673 memset(&hints, 0, sizeof(hints));
674 if (proto != 1) /* 1 == AF_INET - all we support for now */
676 hints.ai_family = AF_INET;
677 hints.ai_socktype = SOCK_STREAM;
678 hints.ai_flags = AI_NUMERICHOST; /*no DNS*/
679 if (getaddrinfo(result[1], result[2], &hints, &res))
683 if (sizeof(client_listen_sa) < res->ai_addrlen)
685 memcpy(&client_listen_sa, res->ai_addr, res->ai_addrlen);
687 debuglog(1, "client wants us to use %s:%u",
688 inet_ntoa(client_listen_sa.sin_addr),
689 htons(client_listen_sa.sin_port));
692 * Configure our own listen socket and tell the server about it
695 connection_mode = EPRT_MODE;
697 debuglog(1, "we want server to use %s:%u",
698 inet_ntoa(server->sa.sin_addr),
699 ntohs(server_listen_sa.sin_port));
701 snprintf(tbuf, sizeof(tbuf), "EPRT |%d|%s|%u|\r\n", 1,
702 inet_ntoa(server->sa.sin_addr),
703 ntohs(server_listen_sa.sin_port));
704 debuglog(1, "to server (modified): %s", tbuf);
708 snprintf(tbuf, sizeof(tbuf),
709 "500 Invalid argument; rejected\r\n");
713 /* we only support AF_INET for now */
715 snprintf(tbuf, sizeof(tbuf),
716 "522 Protocol not supported, use (1)\r\n");
718 snprintf(tbuf, sizeof(tbuf),
719 "501 Protocol not supported\r\n");
726 if (sendbuf == NULL) {
727 debuglog(1, "to client (modified): %s", tbuf);
730 rv = send(client->fd, tbuf + j, i - j, 0);
731 if (rv == -1 && errno != EAGAIN &&
736 } while (j >= 0 && j < i);
738 } else if (!NatMode && (strncasecmp((char *)client->line_buffer,
739 "epsv", strlen("epsv")) == 0)) {
742 * If we aren't in NAT mode, deal with EPSV.
743 * EPSV is a problem - Unlike PASV, the reply from the
744 * server contains *only* a port, we can't modify the reply
745 * to the client and get the client to connect to us without
746 * resorting to using a dynamic rdr rule we have to add in
747 * for the reply to this connection, and take away afterwards.
748 * so this will wait until we have the right solution for rule
749 * additions/deletions in pf.
751 * in the meantime we just tell the client we don't do it,
752 * and most clients should fall back to using PASV.
755 snprintf(tbuf, sizeof(tbuf),
756 "500 EPSV command not understood\r\n");
757 debuglog(1, "to client (modified): %s", tbuf);
761 rv = send(client->fd, tbuf + j, i - j, 0);
762 if (rv == -1 && errno != EAGAIN && errno != EINTR)
766 } while (j >= 0 && j < i);
768 } else if (strncasecmp((char *)client->line_buffer, "port ",
769 strlen("port ")) == 0) {
770 unsigned int values[6];
773 debuglog(1, "Got a PORT command");
775 tailptr = (char *)&client->line_buffer[strlen("port ")];
778 i = sscanf(tailptr, "%u,%u,%u,%u,%u,%u", &values[0],
779 &values[1], &values[2], &values[3], &values[4],
782 syslog(LOG_INFO, "malformed PORT command (%s)",
783 client->line_buffer);
787 for (i = 0; i<6; i++) {
788 if (values[i] > 255) {
790 "malformed PORT command (%s)",
791 client->line_buffer);
796 client_listen_sa.sin_family = AF_INET;
797 client_listen_sa.sin_addr.s_addr = htonl((values[0] << 24) |
798 (values[1] << 16) | (values[2] << 8) |
801 client_listen_sa.sin_port = htons((values[4] << 8) |
803 debuglog(1, "client wants us to use %u.%u.%u.%u:%u",
804 values[0], values[1], values[2], values[3],
805 (values[4] << 8) | values[5]);
808 * Configure our own listen socket and tell the server about it
811 connection_mode = PORT_MODE;
813 debuglog(1, "we want server to use %s:%u",
814 inet_ntoa(server->sa.sin_addr),
815 ntohs(server_listen_sa.sin_port));
817 snprintf(tbuf, sizeof(tbuf), "PORT %u,%u,%u,%u,%u,%u\r\n",
818 ((u_char *)&server->sa.sin_addr.s_addr)[0],
819 ((u_char *)&server->sa.sin_addr.s_addr)[1],
820 ((u_char *)&server->sa.sin_addr.s_addr)[2],
821 ((u_char *)&server->sa.sin_addr.s_addr)[3],
822 ((u_char *)&server_listen_sa.sin_port)[0],
823 ((u_char *)&server_listen_sa.sin_port)[1]);
825 debuglog(1, "to server (modified): %s", tbuf);
829 sendbuf = (char *)client->line_buffer;
832 *send our (possibly modified) control command in sendbuf
833 * on it's way to the server
835 if (sendbuf != NULL) {
839 rv = send(server->fd, sendbuf + j, i - j, 0);
840 if (rv == -1 && errno != EAGAIN && errno != EINTR)
844 } while (j >= 0 && j < i);
849 do_server_reply(struct csiob *server, struct csiob *client)
853 static int continuing = 0;
854 char tbuf[100], *sendbuf, *p;
856 log_control_command((char *)server->line_buffer, 0);
858 if (strlen((char *)server->line_buffer) > 512) {
860 * someone's playing games. Have a cow in the syslogs and
861 * exit - we don't pass this on for fear of hurting
862 * our other end, which might be poorly implemented.
864 syslog(LOG_NOTICE, "long FTP control reply");
869 * Watch out for "227 Entering Passive Mode ..." replies
871 code = strtol((char *)server->line_buffer, &p, 10);
872 if (isspace(server->line_buffer[0]))
874 if (!*(server->line_buffer) || (*p != ' ' && *p != '-')) {
877 syslog(LOG_INFO, "malformed control reply");
880 if (code <= 0 || code > 999) {
883 syslog(LOG_INFO, "invalid server reply code %d", code);
890 if (code == 227 && !NatMode) {
891 unsigned int values[6];
894 debuglog(1, "Got a PASV reply");
895 debuglog(1, "{%s}", (char *)server->line_buffer);
897 tailptr = (char *)strchr((char *)server->line_buffer, '(');
898 if (tailptr == NULL) {
899 tailptr = strrchr((char *)server->line_buffer, ' ');
900 if (tailptr == NULL) {
901 syslog(LOG_NOTICE, "malformed 227 reply");
905 tailptr++; /* skip past space or ( */
909 i = sscanf(tailptr, "%u,%u,%u,%u,%u,%u", &values[0],
910 &values[1], &values[2], &values[3], &values[4],
913 syslog(LOG_INFO, "malformed PASV reply (%s)",
914 client->line_buffer);
917 for (i = 0; i<6; i++)
918 if (values[i] > 255) {
919 syslog(LOG_INFO, "malformed PASV reply(%s)",
920 client->line_buffer);
924 server_listen_sa.sin_family = AF_INET;
925 server_listen_sa.sin_addr.s_addr = htonl((values[0] << 24) |
926 (values[1] << 16) | (values[2] << 8) | (values[3] << 0));
927 server_listen_sa.sin_port = htons((values[4] << 8) |
930 debuglog(1, "server wants us to use %s:%u",
931 inet_ntoa(server_listen_sa.sin_addr), (values[4] << 8) |
935 connection_mode = PASV_MODE;
937 iap = &(proxy_sa.sin_addr);
939 iap = &(server->sa.sin_addr);
941 debuglog(1, "we want client to use %s:%u", inet_ntoa(*iap),
942 htons(client_listen_sa.sin_port));
944 snprintf(tbuf, sizeof(tbuf),
945 "227 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n",
946 ((u_char *)iap)[0], ((u_char *)iap)[1],
947 ((u_char *)iap)[2], ((u_char *)iap)[3],
948 ((u_char *)&client_listen_sa.sin_port)[0],
949 ((u_char *)&client_listen_sa.sin_port)[1]);
950 debuglog(1, "to client (modified): %s", tbuf);
954 sendbuf = (char *)server->line_buffer;
958 * send our (possibly modified) control command in sendbuf
959 * on it's way to the client
964 rv = send(client->fd, sendbuf + j, i - j, 0);
965 if (rv == -1 && errno != EAGAIN && errno != EINTR)
969 } while (j >= 0 && j < i);
974 main(int argc, char *argv[])
976 struct csiob client_iob, server_iob;
977 struct sigaction new_sa, old_sa;
978 int sval, ch, flags, i;
981 long timeout_seconds = 0;
984 int use_tcpwrapper = 0;
987 while ((ch = getopt(argc, argv, "a:D:g:m:M:R:S:t:u:AnVwr")) != -1) {
993 if ((Bind_Addr = inet_addr(optarg)) == INADDR_NONE) {
995 "%s: invalid address", optarg);
1000 AnonFtpOnly = 1; /* restrict to anon usernames only */
1003 Debug_Level = strtol(optarg, &p, 10);
1011 min_port = strtol(optarg, &p, 10);
1014 if (min_port < 0 || min_port > USHRT_MAX)
1018 max_port = strtol(optarg, &p, 10);
1021 if (max_port < 0 || max_port > USHRT_MAX)
1025 NatMode = 1; /* pass all passives, we're using NAT */
1028 Use_Rdns = 1; /* look up hostnames */
1035 if ((s = strdup(optarg)) == NULL) {
1037 "Insufficient memory (malloc failed)");
1038 exit(EX_UNAVAILABLE);
1040 memset(&real_server_sa, 0, sizeof(real_server_sa));
1041 real_server_sa.sin_len = sizeof(struct sockaddr_in);
1042 real_server_sa.sin_family = AF_INET;
1045 real_server_sa.sin_port = htons(21);
1047 long port = strtol(t + 1, &p, 10);
1049 if (*p || port <= 0 || port > 65535)
1051 real_server_sa.sin_port = htons(port);
1054 real_server_sa.sin_addr.s_addr = inet_addr(s);
1055 if (real_server_sa.sin_addr.s_addr == INADDR_NONE)
1062 if (!inet_aton(optarg, &src_addr))
1066 timeout_seconds = strtol(optarg, &p, 10);
1078 use_tcpwrapper = 1; /* do the libwrap thing */
1080 #endif /* LIBWRAP */
1089 if (max_port < min_port)
1092 openlog(__progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
1097 memset(&client_iob, 0, sizeof(client_iob));
1098 memset(&server_iob, 0, sizeof(server_iob));
1100 if (get_proxy_env(0, &real_server_sa, &client_iob.sa,
1105 * We may now drop root privs, as we have done our ioctl for
1106 * pf. If we do drop root, we can't make backchannel connections
1107 * for PORT and EPRT come from port 20, which is not strictly
1108 * RFC compliant. This shouldn't cause problems for all but
1109 * the stupidest ftp clients and the stupidest packet filters.
1114 * We check_host after get_proxy_env so that checks are done
1115 * against the original destination endpoint, not the endpoint
1116 * of our side of the rdr. This allows the use of tcpwrapper
1117 * rules to restrict destinations as well as sources of connections
1123 flags = NI_NUMERICHOST | NI_NUMERICSERV;
1125 i = getnameinfo((struct sockaddr *)&client_iob.sa,
1126 sizeof(client_iob.sa), ClientName, sizeof(ClientName), NULL, 0,
1129 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
1130 debuglog(2, "name resolution failure (client)");
1134 i = getnameinfo((struct sockaddr *)&real_server_sa,
1135 sizeof(real_server_sa), RealServerName, sizeof(RealServerName),
1138 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
1139 debuglog(2, "name resolution failure (server)");
1144 if (use_tcpwrapper && !check_host(&client_iob.sa, &real_server_sa))
1150 syslog(LOG_INFO, "accepted connection from %s:%u to %s:%u", ClientName,
1151 ntohs(client_iob.sa.sin_port), RealServerName,
1152 ntohs(real_server_sa.sin_port));
1154 server_iob.fd = get_backchannel_socket(SOCK_STREAM, min_port, max_port,
1155 -1, 1, &server_iob.sa);
1157 if (connect(server_iob.fd, (struct sockaddr *)&real_server_sa,
1158 sizeof(real_server_sa)) != 0) {
1159 syslog(LOG_INFO, "cannot connect to %s:%u (%m)", RealServerName,
1160 ntohs(real_server_sa.sin_port));
1165 * Now that we are connected to the real server, get the name
1166 * of our end of the server socket so we know our IP address
1167 * from the real server's perspective.
1169 salen = sizeof(server_iob.sa);
1170 getsockname(server_iob.fd, (struct sockaddr *)&server_iob.sa, &salen);
1172 i = getnameinfo((struct sockaddr *)&server_iob.sa,
1173 sizeof(server_iob.sa), OurName, sizeof(OurName), NULL, 0, flags);
1175 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
1176 debuglog(2, "name resolution failure (local)");
1180 debuglog(1, "local socket is %s:%u", OurName,
1181 ntohs(server_iob.sa.sin_port));
1183 /* ignore SIGPIPE */
1184 bzero(&new_sa, sizeof(new_sa));
1185 new_sa.sa_handler = SIG_IGN;
1186 (void)sigemptyset(&new_sa.sa_mask);
1187 new_sa.sa_flags = SA_RESTART;
1188 if (sigaction(SIGPIPE, &new_sa, &old_sa) != 0) {
1189 syslog(LOG_ERR, "sigaction() failed (%m)");
1193 if (setsockopt(client_iob.fd, SOL_SOCKET, SO_OOBINLINE, (char *)&one,
1194 sizeof(one)) == -1) {
1195 syslog(LOG_NOTICE, "cannot set SO_OOBINLINE (%m)");
1199 client_iob.line_buffer_size = STARTBUFSIZE;
1200 client_iob.line_buffer = malloc(client_iob.line_buffer_size);
1201 client_iob.io_buffer_size = STARTBUFSIZE;
1202 client_iob.io_buffer = malloc(client_iob.io_buffer_size);
1203 client_iob.next_byte = 0;
1204 client_iob.io_buffer_len = 0;
1205 client_iob.alive = 1;
1206 client_iob.who = "client";
1207 client_iob.send_oob_flags = 0;
1208 client_iob.real_sa = client_iob.sa;
1210 server_iob.line_buffer_size = STARTBUFSIZE;
1211 server_iob.line_buffer = malloc(server_iob.line_buffer_size);
1212 server_iob.io_buffer_size = STARTBUFSIZE;
1213 server_iob.io_buffer = malloc(server_iob.io_buffer_size);
1214 server_iob.next_byte = 0;
1215 server_iob.io_buffer_len = 0;
1216 server_iob.alive = 1;
1217 server_iob.who = "server";
1218 server_iob.send_oob_flags = MSG_OOB;
1219 server_iob.real_sa = real_server_sa;
1221 if (client_iob.line_buffer == NULL || client_iob.io_buffer == NULL ||
1222 server_iob.line_buffer == NULL || server_iob.io_buffer == NULL) {
1223 syslog (LOG_NOTICE, "insufficient memory");
1224 exit(EX_UNAVAILABLE);
1227 while (client_iob.alive || server_iob.alive) {
1231 if (client_iob.fd > maxfd)
1232 maxfd = client_iob.fd;
1233 if (client_listen_socket > maxfd)
1234 maxfd = client_listen_socket;
1235 if (client_data_socket > maxfd)
1236 maxfd = client_data_socket;
1237 if (server_iob.fd > maxfd)
1238 maxfd = server_iob.fd;
1239 if (server_listen_socket > maxfd)
1240 maxfd = server_listen_socket;
1241 if (server_data_socket > maxfd)
1242 maxfd = server_data_socket;
1244 debuglog(3, "client is %s; server is %s",
1245 client_iob.alive ? "alive" : "dead",
1246 server_iob.alive ? "alive" : "dead");
1248 fdsp = (fd_set *)calloc(howmany(maxfd + 1, NFDBITS),
1251 syslog(LOG_NOTICE, "insufficient memory");
1252 exit(EX_UNAVAILABLE);
1255 if (client_iob.alive && telnet_getline(&client_iob,
1257 debuglog(3, "client line buffer is \"%s\"",
1258 (char *)client_iob.line_buffer);
1259 if (client_iob.line_buffer[0] != '\0')
1260 do_client_cmd(&client_iob, &server_iob);
1261 } else if (server_iob.alive && telnet_getline(&server_iob,
1263 debuglog(3, "server line buffer is \"%s\"",
1264 (char *)server_iob.line_buffer);
1265 if (server_iob.line_buffer[0] != '\0')
1266 do_server_reply(&server_iob, &client_iob);
1268 if (client_iob.alive) {
1269 FD_SET(client_iob.fd, fdsp);
1270 if (client_listen_socket >= 0)
1271 FD_SET(client_listen_socket, fdsp);
1272 if (client_data_socket >= 0)
1273 FD_SET(client_data_socket, fdsp);
1275 if (server_iob.alive) {
1276 FD_SET(server_iob.fd, fdsp);
1277 if (server_listen_socket >= 0)
1278 FD_SET(server_listen_socket, fdsp);
1279 if (server_data_socket >= 0)
1280 FD_SET(server_data_socket, fdsp);
1282 tv.tv_sec = timeout_seconds;
1286 sval = select(maxfd + 1, fdsp, NULL, NULL,
1287 (tv.tv_sec == 0) ? NULL : &tv);
1290 * This proxy has timed out. Expire it
1291 * quietly with an obituary in the syslogs
1292 * for any passing mourners.
1295 "timeout: no data for %ld seconds",
1300 if (errno == EINTR || errno == EAGAIN)
1303 "select() failed (%m)");
1306 if (client_data_socket >= 0 &&
1307 FD_ISSET(client_data_socket, fdsp)) {
1310 debuglog(3, "transfer: client to server");
1311 rval = xfer_data("client to server",
1314 client_iob.sa.sin_addr,
1315 real_server_sa.sin_addr);
1317 close_client_data();
1318 close_server_data();
1321 client_data_bytes += rval;
1323 if (server_data_socket >= 0 &&
1324 FD_ISSET(server_data_socket, fdsp)) {
1327 debuglog(3, "transfer: server to client");
1328 rval = xfer_data("server to client",
1331 real_server_sa.sin_addr,
1332 client_iob.sa.sin_addr);
1334 close_client_data();
1335 close_server_data();
1338 server_data_bytes += rval;
1340 if (server_listen_socket >= 0 &&
1341 FD_ISSET(server_listen_socket, fdsp)) {
1342 connect_port_backchannel();
1344 if (client_listen_socket >= 0 &&
1345 FD_ISSET(client_listen_socket, fdsp)) {
1346 connect_pasv_backchannel();
1348 if (client_iob.alive &&
1349 FD_ISSET(client_iob.fd, fdsp)) {
1350 client_iob.data_available = 1;
1352 if (server_iob.alive &&
1353 FD_ISSET(server_iob.fd, fdsp)) {
1354 server_iob.data_available = 1;
1358 if (client_iob.got_eof) {
1359 shutdown(server_iob.fd, 1);
1360 shutdown(client_iob.fd, 0);
1361 client_iob.got_eof = 0;
1362 client_iob.alive = 0;
1364 if (server_iob.got_eof) {
1365 shutdown(client_iob.fd, 1);
1366 shutdown(server_iob.fd, 0);
1367 server_iob.got_eof = 0;
1368 server_iob.alive = 0;
1373 syslog(LOG_INFO, "session ended");