1 /* $OpenBSD: ftp-proxy.c,v 1.35 2004/03/14 21:51:44 dhartmei Exp $ */
2 /* $DragonFly: src/libexec/ftp-proxy/ftp-proxy.c,v 1.1 2004/09/21 21:25:28 joerg Exp $ */
5 * Copyright (c) 1996-2001
6 * Obtuse Systems Corporation. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the Obtuse Systems nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY OBTUSE SYSTEMS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL OBTUSE SYSTEMS CORPORATION OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 * ftp proxy, Originally based on juniper_ftp_proxy from the Obtuse
36 * Systems juniper firewall, written by Dan Boulet <danny@obtuse.com>
37 * and Bob Beck <beck@obtuse.com>
39 * This version basically passes everything through unchanged except
40 * for the PORT and the * "227 Entering Passive Mode" reply.
42 * A PORT command is handled by noting the IP address and port number
43 * specified and then configuring a listen port on some very high port
44 * number and telling the server about it using a PORT message.
45 * We then watch for an in-bound connection on the port from the server
46 * and connect to the client's port when it happens.
48 * A "227 Entering Passive Mode" reply is handled by noting the IP address
49 * and port number specified and then configuring a listen port on some
50 * very high port number and telling the client about it using a
51 * "227 Entering Passive Mode" reply.
52 * We then watch for an in-bound connection on the port from the client
53 * and connect to the server's port when it happens.
55 * supports tcp wrapper lookups/access control with the -w flag using
56 * the real destination address - the tcp wrapper stuff is done after
57 * the real destination address is retrieved from pf
63 * Plenty, this is very basic, with the idea to get it in clean first.
65 * - IPv6 and EPASV support
66 * - Content filter support
67 * - filename filter support
68 * - per-user rules perhaps.
71 #include <sys/param.h>
73 #include <sys/socket.h>
76 #include <netinet/in.h>
78 #include <arpa/inet.h>
98 int allow_severity = LOG_INFO;
99 int deny_severity = LOG_NOTICE;
102 int min_port = IPPORT_HIFIRSTAUTO;
103 int max_port = IPPORT_HILASTAUTO;
105 #define STARTBUFSIZE 1024 /* Must be at least 3 */
108 * Variables used to support PORT mode connections.
110 * This gets a bit complicated.
112 * If PORT mode is on then client_listen_sa describes the socket that
113 * the real client is listening on and server_listen_sa describes the
114 * socket that we are listening on (waiting for the real server to connect
117 * If PASV mode is on then client_listen_sa describes the socket that
118 * we are listening on (waiting for the real client to connect to us on)
119 * and server_listen_sa describes the socket that the real server is
122 * If the socket we are listening on gets a connection then we connect
123 * to the other side's socket. Similarly, if a connected socket is
124 * shutdown then we shutdown the other side's socket.
127 double xfer_start_time;
129 struct sockaddr_in real_server_sa;
130 struct sockaddr_in client_listen_sa;
131 struct sockaddr_in server_listen_sa;
133 int client_listen_socket = -1; /* Only used in PASV mode */
134 int client_data_socket = -1; /* Connected socket to real client */
135 int server_listen_socket = -1; /* Only used in PORT mode */
136 int server_data_socket = -1; /* Connected socket to real server */
137 int client_data_bytes, server_data_bytes;
143 char ClientName[NI_MAXHOST];
144 char RealServerName[NI_MAXHOST];
145 char OurName[NI_MAXHOST];
147 const char *User = "proxy";
150 extern int Debug_Level;
152 extern in_addr_t Bind_Addr;
153 extern char *__progname;
163 connection_mode_t connection_mode;
165 extern void debuglog(int debug_level, const char *fmt, ...);
166 double wallclock_time(void);
167 void show_xfer_stats(void);
168 void log_control_command(const char *cmd, int client);
169 int new_dataconn(int server);
170 void do_client_cmd(struct csiob *client, struct csiob *server);
171 void do_server_reply(struct csiob *server, struct csiob *client);
177 "usage: %s [-AnrVw] [-a address] [-D debuglevel [-g group]"
178 " [-M maxport] [-m minport] [-t timeout] [-u user]", __progname);
183 close_client_data(void)
185 if (client_data_socket >= 0) {
186 shutdown(client_data_socket, 2);
187 close(client_data_socket);
188 client_data_socket = -1;
193 close_server_data(void)
195 if (server_data_socket >= 0) {
196 shutdown(server_data_socket, 2);
197 close(server_data_socket);
198 server_data_socket = -1;
213 syslog(LOG_ERR, "cannot find user %s", User);
221 gr = getgrnam(Group);
223 syslog(LOG_ERR, "cannot find group %s", Group);
229 if (gid != 0 && (setegid(gid) == -1 || setgid(gid) == -1)) {
230 syslog(LOG_ERR, "cannot drop group privs (%m)");
234 if (uid != 0 && (seteuid(uid) == -1 || setuid(uid) == -1)) {
235 syslog(LOG_ERR, "cannot drop root privs (%m)");
242 * Check a connection against the tcpwrapper, log if we're going to
243 * reject it, returns: 0 -> reject, 1 -> accept. We add in hostnames
244 * if we are set to do reverse DNS, otherwise no.
247 check_host(struct sockaddr_in *client_sin, struct sockaddr_in *server_sin)
249 char cname[NI_MAXHOST];
250 char sname[NI_MAXHOST];
251 struct request_info request;
254 request_init(&request, RQ_DAEMON, __progname, RQ_CLIENT_SIN,
255 client_sin, RQ_SERVER_SIN, server_sin, RQ_CLIENT_ADDR,
256 inet_ntoa(client_sin->sin_addr), 0);
260 * We already looked these up, but we have to do it again
261 * for tcp wrapper, to ensure that we get the DNS name, since
262 * the tcp wrapper cares about these things, and we don't
263 * want to pass in a printed address as a name.
265 i = getnameinfo((struct sockaddr *) &client_sin->sin_addr,
266 sizeof(&client_sin->sin_addr), cname, sizeof(cname),
267 NULL, 0, NI_NAMEREQD);
269 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN)
270 strlcpy(cname, STRING_UNKNOWN, sizeof(cname));
272 i = getnameinfo((struct sockaddr *)&server_sin->sin_addr,
273 sizeof(&server_sin->sin_addr), sname, sizeof(sname),
274 NULL, 0, NI_NAMEREQD);
276 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN)
277 strlcpy(sname, STRING_UNKNOWN, sizeof(sname));
280 * ensure the TCP wrapper doesn't start doing
281 * reverse DNS lookups if we aren't supposed to.
283 strlcpy(cname, STRING_UNKNOWN, sizeof(cname));
284 strlcpy(sname, STRING_UNKNOWN, sizeof(sname));
287 request_set(&request, RQ_SERVER_ADDR, inet_ntoa(server_sin->sin_addr),
289 request_set(&request, RQ_CLIENT_NAME, cname, RQ_SERVER_NAME, sname, 0);
291 if (!hosts_access(&request)) {
292 syslog(LOG_NOTICE, "tcpwrappers rejected: %s -> %s",
293 ClientName, RealServerName);
305 gettimeofday(&tv, NULL);
306 return(tv.tv_sec + tv.tv_usec / 1e6);
310 * Show the stats for this data transfer
313 show_xfer_stats(void)
323 delta = wallclock_time() - xfer_start_time;
328 if (client_data_bytes == 0 && server_data_bytes == 0) {
330 "data transfer complete (no bytes transferred)");
339 idelta = delta + 0.5;
340 if (idelta >= 60*60) {
341 i = snprintf(tbuf, len,
342 "data transfer complete (%dh %dm %ds",
343 idelta / (60*60), (idelta % (60*60)) / 60,
349 i = snprintf(tbuf, len,
350 "data transfer complete (%dm %ds", idelta / 60,
357 i = snprintf(tbuf, len, "data transfer complete (%.1fs",
364 if (client_data_bytes > 0) {
365 i = snprintf(&tbuf[strlen(tbuf)], len,
366 ", %d bytes to server) (%.1fKB/s", client_data_bytes,
367 (client_data_bytes / delta) / (double)1024);
372 if (server_data_bytes > 0) {
373 i = snprintf(&tbuf[strlen(tbuf)], len,
374 ", %d bytes to client) (%.1fKB/s", server_data_bytes,
375 (server_data_bytes / delta) / (double)1024);
380 strlcat(tbuf, ")", sizeof(tbuf));
382 syslog(LOG_INFO, "%s", tbuf);
386 log_control_command (const char *cmd, int client)
388 /* log an ftp control command or reply */
389 const char *logstring;
390 int level = LOG_DEBUG;
395 /* don't log passwords */
396 if (strncasecmp(cmd, "pass ", 5) == 0)
397 logstring = "PASS XXXX";
401 /* log interesting stuff at LOG_INFO, rest at LOG_DEBUG */
402 if ((strncasecmp(cmd, "user ", 5) == 0) ||
403 (strncasecmp(cmd, "retr ", 5) == 0) ||
404 (strncasecmp(cmd, "cwd ", 4) == 0) ||
405 (strncasecmp(cmd, "stor " ,5) == 0))
408 syslog(level, "%s %s", client ? "client:" : " server:",
413 * set ourselves up for a new data connection. Direction is toward client if
414 * "server" is 0, towards server otherwise.
417 new_dataconn(int server)
420 * Close existing data conn.
423 if (client_listen_socket != -1) {
424 close(client_listen_socket);
425 client_listen_socket = -1;
429 if (server_listen_socket != -1) {
430 close(server_listen_socket);
431 server_listen_socket = -1;
436 bzero(&server_listen_sa, sizeof(server_listen_sa));
437 server_listen_socket = get_backchannel_socket(SOCK_STREAM,
438 min_port, max_port, -1, 1, &server_listen_sa);
440 if (server_listen_socket == -1) {
441 syslog(LOG_INFO, "server socket bind() failed (%m)");
444 if (listen(server_listen_socket, 5) != 0) {
445 syslog(LOG_INFO, "server socket listen() failed (%m)");
449 bzero(&client_listen_sa, sizeof(client_listen_sa));
450 client_listen_socket = get_backchannel_socket(SOCK_STREAM,
451 min_port, max_port, -1, 1, &client_listen_sa);
453 if (client_listen_socket == -1) {
455 "cannot get client listen socket (%m)");
458 if (listen(client_listen_socket, 5) != 0) {
460 "cannot listen on client socket (%m)");
468 connect_pasv_backchannel(void)
470 struct sockaddr_in listen_sa;
474 * We are about to accept a connection from the client.
475 * This is a PASV data connection.
477 debuglog(2, "client listen socket ready");
482 salen = sizeof(listen_sa);
483 client_data_socket = accept(client_listen_socket,
484 (struct sockaddr *)&listen_sa, &salen);
486 if (client_data_socket < 0) {
487 syslog(LOG_NOTICE, "accept() failed (%m)");
490 close(client_listen_socket);
491 client_listen_socket = -1;
492 memset(&listen_sa, 0, sizeof(listen_sa));
494 server_data_socket = get_backchannel_socket(SOCK_STREAM, min_port,
495 max_port, -1, 1, &listen_sa);
496 if (server_data_socket < 0) {
497 syslog(LOG_NOTICE, "get_backchannel_socket() failed (%m)");
500 if (connect(server_data_socket, (struct sockaddr *) &server_listen_sa,
501 sizeof(server_listen_sa)) != 0) {
502 syslog(LOG_NOTICE, "connect() failed (%m)");
505 client_data_bytes = 0;
506 server_data_bytes = 0;
507 xfer_start_time = wallclock_time();
511 connect_port_backchannel(void)
513 struct sockaddr_in listen_sa;
517 * We are about to accept a connection from the server.
518 * This is a PORT or EPRT data connection.
520 debuglog(2, "server listen socket ready");
525 salen = sizeof(listen_sa);
526 server_data_socket = accept(server_listen_socket,
527 (struct sockaddr *)&listen_sa, &salen);
528 if (server_data_socket < 0) {
529 syslog(LOG_NOTICE, "accept() failed (%m)");
532 close(server_listen_socket);
533 server_listen_socket = -1;
537 * We're not running as root, so we get a backchannel
538 * socket bound in our designated range, instead of
539 * getting one bound to port 20 - This is deliberately
542 bzero(&listen_sa.sin_addr, sizeof(struct in_addr));
543 client_data_socket = get_backchannel_socket(SOCK_STREAM,
544 min_port, max_port, -1, 1, &listen_sa);
545 if (client_data_socket < 0) {
546 syslog(LOG_NOTICE, "get_backchannel_socket() failed (%m)");
553 * We're root, get our backchannel socket bound to port
554 * 20 here, so we're fully RFC compliant.
556 client_data_socket = socket(AF_INET, SOCK_STREAM, 0);
559 listen_sa.sin_family = AF_INET;
560 bzero(&listen_sa.sin_addr, sizeof(struct in_addr));
561 listen_sa.sin_port = htons(20);
563 if (setsockopt(client_data_socket, SOL_SOCKET, SO_REUSEADDR,
564 &salen, sizeof(salen)) == -1) {
565 syslog(LOG_NOTICE, "setsockopt() failed (%m)");
569 if (bind(client_data_socket, (struct sockaddr *)&listen_sa,
570 sizeof(listen_sa)) == - 1) {
571 syslog(LOG_NOTICE, "data channel bind() failed (%m)");
576 if (connect(client_data_socket, (struct sockaddr *) &client_listen_sa,
577 sizeof(client_listen_sa)) != 0) {
578 syslog(LOG_INFO, "cannot connect data channel (%m)");
582 client_data_bytes = 0;
583 server_data_bytes = 0;
584 xfer_start_time = wallclock_time();
588 do_client_cmd(struct csiob *client, struct csiob *server)
592 char *sendbuf = NULL;
594 log_control_command((char *)client->line_buffer, 1);
596 /* client->line_buffer is an ftp control command.
597 * There is no reason for these to be very long.
598 * In the interest of limiting buffer overrun attempts,
599 * we catch them here.
601 if (strlen((char *)client->line_buffer) > 512) {
602 syslog(LOG_NOTICE, "excessively long control command");
607 * Check the client user provided if needed
609 if (AnonFtpOnly && strncasecmp((char *)client->line_buffer, "user ",
610 strlen("user ")) == 0) {
613 cp = (char *) client->line_buffer + strlen("user ");
614 if ((strcasecmp(cp, "ftp\r\n") != 0) &&
615 (strcasecmp(cp, "anonymous\r\n") != 0)) {
617 * this isn't anonymous - give the client an
618 * error before they send a password
620 snprintf(tbuf, sizeof(tbuf),
621 "500 Only anonymous FTP is allowed\r\n");
625 rv = send(client->fd, tbuf + j, i - j, 0);
626 if (rv == -1 && errno != EAGAIN &&
631 } while (j >= 0 && j < i);
634 sendbuf = (char *)client->line_buffer;
635 } else if ((strncasecmp((char *)client->line_buffer, "eprt ",
636 strlen("eprt ")) == 0)) {
638 /* Watch out for EPRT commands */
639 char *line = NULL, *q, *p, *result[3], delim;
640 struct addrinfo hints, *res = NULL;
644 line = strdup((char *)client->line_buffer+strlen("eprt "));
646 syslog(LOG_ERR, "insufficient memory");
647 exit(EX_UNAVAILABLE);
653 memset(result,0, sizeof(result));
654 for (i = 0; i < 3; i++) {
655 q = strchr(p, delim);
656 if (!q || *q != delim)
663 proto = strtoul(result[0], &p, 10);
664 if (!*result[0] || *p)
667 memset(&hints, 0, sizeof(hints));
668 if (proto != 1) /* 1 == AF_INET - all we support for now */
670 hints.ai_family = AF_INET;
671 hints.ai_socktype = SOCK_STREAM;
672 hints.ai_flags = AI_NUMERICHOST; /*no DNS*/
673 if (getaddrinfo(result[1], result[2], &hints, &res))
677 if (sizeof(client_listen_sa) < res->ai_addrlen)
679 memcpy(&client_listen_sa, res->ai_addr, res->ai_addrlen);
681 debuglog(1, "client wants us to use %s:%u",
682 inet_ntoa(client_listen_sa.sin_addr),
683 htons(client_listen_sa.sin_port));
686 * Configure our own listen socket and tell the server about it
689 connection_mode = EPRT_MODE;
691 debuglog(1, "we want server to use %s:%u",
692 inet_ntoa(server->sa.sin_addr),
693 ntohs(server_listen_sa.sin_port));
695 snprintf(tbuf, sizeof(tbuf), "EPRT |%d|%s|%u|\r\n", 1,
696 inet_ntoa(server->sa.sin_addr),
697 ntohs(server_listen_sa.sin_port));
698 debuglog(1, "to server (modified): %s", tbuf);
702 snprintf(tbuf, sizeof(tbuf),
703 "500 Invalid argument; rejected\r\n");
707 /* we only support AF_INET for now */
709 snprintf(tbuf, sizeof(tbuf),
710 "522 Protocol not supported, use (1)\r\n");
712 snprintf(tbuf, sizeof(tbuf),
713 "501 Protocol not supported\r\n");
720 if (sendbuf == NULL) {
721 debuglog(1, "to client (modified): %s", tbuf);
724 rv = send(client->fd, tbuf + j, i - j, 0);
725 if (rv == -1 && errno != EAGAIN &&
730 } while (j >= 0 && j < i);
732 } else if (!NatMode && (strncasecmp((char *)client->line_buffer,
733 "epsv", strlen("epsv")) == 0)) {
736 * If we aren't in NAT mode, deal with EPSV.
737 * EPSV is a problem - Unlike PASV, the reply from the
738 * server contains *only* a port, we can't modify the reply
739 * to the client and get the client to connect to us without
740 * resorting to using a dynamic rdr rule we have to add in
741 * for the reply to this connection, and take away afterwards.
742 * so this will wait until we have the right solution for rule
743 * additions/deletions in pf.
745 * in the meantime we just tell the client we don't do it,
746 * and most clients should fall back to using PASV.
749 snprintf(tbuf, sizeof(tbuf),
750 "500 EPSV command not understood\r\n");
751 debuglog(1, "to client (modified): %s", tbuf);
755 rv = send(client->fd, tbuf + j, i - j, 0);
756 if (rv == -1 && errno != EAGAIN && errno != EINTR)
760 } while (j >= 0 && j < i);
762 } else if (strncasecmp((char *)client->line_buffer, "port ",
763 strlen("port ")) == 0) {
764 unsigned int values[6];
767 debuglog(1, "Got a PORT command");
769 tailptr = (char *)&client->line_buffer[strlen("port ")];
772 i = sscanf(tailptr, "%u,%u,%u,%u,%u,%u", &values[0],
773 &values[1], &values[2], &values[3], &values[4],
776 syslog(LOG_INFO, "malformed PORT command (%s)",
777 client->line_buffer);
781 for (i = 0; i<6; i++) {
782 if (values[i] > 255) {
784 "malformed PORT command (%s)",
785 client->line_buffer);
790 client_listen_sa.sin_family = AF_INET;
791 client_listen_sa.sin_addr.s_addr = htonl((values[0] << 24) |
792 (values[1] << 16) | (values[2] << 8) |
795 client_listen_sa.sin_port = htons((values[4] << 8) |
797 debuglog(1, "client wants us to use %u.%u.%u.%u:%u",
798 values[0], values[1], values[2], values[3],
799 (values[4] << 8) | values[5]);
802 * Configure our own listen socket and tell the server about it
805 connection_mode = PORT_MODE;
807 debuglog(1, "we want server to use %s:%u",
808 inet_ntoa(server->sa.sin_addr),
809 ntohs(server_listen_sa.sin_port));
811 snprintf(tbuf, sizeof(tbuf), "PORT %u,%u,%u,%u,%u,%u\r\n",
812 ((u_char *)&server->sa.sin_addr.s_addr)[0],
813 ((u_char *)&server->sa.sin_addr.s_addr)[1],
814 ((u_char *)&server->sa.sin_addr.s_addr)[2],
815 ((u_char *)&server->sa.sin_addr.s_addr)[3],
816 ((u_char *)&server_listen_sa.sin_port)[0],
817 ((u_char *)&server_listen_sa.sin_port)[1]);
819 debuglog(1, "to server (modified): %s", tbuf);
823 sendbuf = (char *)client->line_buffer;
826 *send our (possibly modified) control command in sendbuf
827 * on it's way to the server
829 if (sendbuf != NULL) {
833 rv = send(server->fd, sendbuf + j, i - j, 0);
834 if (rv == -1 && errno != EAGAIN && errno != EINTR)
838 } while (j >= 0 && j < i);
843 do_server_reply(struct csiob *server, struct csiob *client)
847 static int continuing = 0;
848 char tbuf[100], *sendbuf, *p;
850 log_control_command((char *)server->line_buffer, 0);
852 if (strlen((char *)server->line_buffer) > 512) {
854 * someone's playing games. Have a cow in the syslogs and
855 * exit - we don't pass this on for fear of hurting
856 * our other end, which might be poorly implemented.
858 syslog(LOG_NOTICE, "long FTP control reply");
863 * Watch out for "227 Entering Passive Mode ..." replies
865 code = strtol((char *)server->line_buffer, &p, 10);
866 if (isspace(server->line_buffer[0]))
868 if (!*(server->line_buffer) || (*p != ' ' && *p != '-')) {
871 syslog(LOG_INFO, "malformed control reply");
874 if (code <= 0 || code > 999) {
877 syslog(LOG_INFO, "invalid server reply code %d", code);
884 if (code == 227 && !NatMode) {
885 unsigned int values[6];
888 debuglog(1, "Got a PASV reply");
889 debuglog(1, "{%s}", (char *)server->line_buffer);
891 tailptr = (char *)strchr((char *)server->line_buffer, '(');
892 if (tailptr == NULL) {
893 tailptr = strrchr((char *)server->line_buffer, ' ');
894 if (tailptr == NULL) {
895 syslog(LOG_NOTICE, "malformed 227 reply");
899 tailptr++; /* skip past space or ( */
903 i = sscanf(tailptr, "%u,%u,%u,%u,%u,%u", &values[0],
904 &values[1], &values[2], &values[3], &values[4],
907 syslog(LOG_INFO, "malformed PASV reply (%s)",
908 client->line_buffer);
911 for (i = 0; i<6; i++)
912 if (values[i] > 255) {
913 syslog(LOG_INFO, "malformed PASV reply(%s)",
914 client->line_buffer);
918 server_listen_sa.sin_family = AF_INET;
919 server_listen_sa.sin_addr.s_addr = htonl((values[0] << 24) |
920 (values[1] << 16) | (values[2] << 8) | (values[3] << 0));
921 server_listen_sa.sin_port = htons((values[4] << 8) |
924 debuglog(1, "server wants us to use %s:%u",
925 inet_ntoa(server_listen_sa.sin_addr), (values[4] << 8) |
929 connection_mode = PASV_MODE;
930 iap = &(server->sa.sin_addr);
932 debuglog(1, "we want client to use %s:%u", inet_ntoa(*iap),
933 htons(client_listen_sa.sin_port));
935 snprintf(tbuf, sizeof(tbuf),
936 "227 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n",
937 ((u_char *)iap)[0], ((u_char *)iap)[1],
938 ((u_char *)iap)[2], ((u_char *)iap)[3],
939 ((u_char *)&client_listen_sa.sin_port)[0],
940 ((u_char *)&client_listen_sa.sin_port)[1]);
941 debuglog(1, "to client (modified): %s", tbuf);
945 sendbuf = (char *)server->line_buffer;
949 * send our (possibly modified) control command in sendbuf
950 * on it's way to the client
955 rv = send(client->fd, sendbuf + j, i - j, 0);
956 if (rv == -1 && errno != EAGAIN && errno != EINTR)
960 } while (j >= 0 && j < i);
965 main(int argc, char *argv[])
967 struct csiob client_iob, server_iob;
968 struct sigaction new_sa, old_sa;
969 int sval, ch, flags, i;
972 long timeout_seconds = 0;
975 int use_tcpwrapper = 0;
978 while ((ch = getopt(argc, argv, "a:D:g:m:M:t:u:AnVwr")) != -1) {
984 if ((Bind_Addr = inet_addr(optarg)) == INADDR_NONE) {
986 "%s: invalid address", optarg);
991 AnonFtpOnly = 1; /* restrict to anon usernames only */
994 Debug_Level = strtol(optarg, &p, 10);
1002 min_port = strtol(optarg, &p, 10);
1005 if (min_port < 0 || min_port > USHRT_MAX)
1009 max_port = strtol(optarg, &p, 10);
1012 if (max_port < 0 || max_port > USHRT_MAX)
1016 NatMode = 1; /* pass all passives, we're using NAT */
1019 Use_Rdns = 1; /* look up hostnames */
1022 timeout_seconds = strtol(optarg, &p, 10);
1034 use_tcpwrapper = 1; /* do the libwrap thing */
1036 #endif /* LIBWRAP */
1045 if (max_port < min_port)
1048 openlog(__progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
1053 memset(&client_iob, 0, sizeof(client_iob));
1054 memset(&server_iob, 0, sizeof(server_iob));
1056 if (get_proxy_env(0, &real_server_sa, &client_iob.sa) == -1)
1060 * We may now drop root privs, as we have done our ioctl for
1061 * pf. If we do drop root, we can't make backchannel connections
1062 * for PORT and EPRT come from port 20, which is not strictly
1063 * RFC compliant. This shouldn't cause problems for all but
1064 * the stupidest ftp clients and the stupidest packet filters.
1069 * We check_host after get_proxy_env so that checks are done
1070 * against the original destination endpoint, not the endpoint
1071 * of our side of the rdr. This allows the use of tcpwrapper
1072 * rules to restrict destinations as well as sources of connections
1078 flags = NI_NUMERICHOST | NI_NUMERICSERV;
1080 i = getnameinfo((struct sockaddr *)&client_iob.sa,
1081 sizeof(client_iob.sa), ClientName, sizeof(ClientName), NULL, 0,
1084 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
1085 debuglog(2, "name resolution failure (client)");
1089 i = getnameinfo((struct sockaddr *)&real_server_sa,
1090 sizeof(real_server_sa), RealServerName, sizeof(RealServerName),
1093 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
1094 debuglog(2, "name resolution failure (server)");
1099 if (use_tcpwrapper && !check_host(&client_iob.sa, &real_server_sa))
1105 syslog(LOG_INFO, "accepted connection from %s:%u to %s:%u", ClientName,
1106 ntohs(client_iob.sa.sin_port), RealServerName,
1107 ntohs(real_server_sa.sin_port));
1109 server_iob.fd = get_backchannel_socket(SOCK_STREAM, min_port, max_port,
1110 -1, 1, &server_iob.sa);
1112 if (connect(server_iob.fd, (struct sockaddr *)&real_server_sa,
1113 sizeof(real_server_sa)) != 0) {
1114 syslog(LOG_INFO, "cannot connect to %s:%u (%m)", RealServerName,
1115 ntohs(real_server_sa.sin_port));
1120 * Now that we are connected to the real server, get the name
1121 * of our end of the server socket so we know our IP address
1122 * from the real server's perspective.
1124 salen = sizeof(server_iob.sa);
1125 getsockname(server_iob.fd, (struct sockaddr *)&server_iob.sa, &salen);
1127 i = getnameinfo((struct sockaddr *)&server_iob.sa,
1128 sizeof(server_iob.sa), OurName, sizeof(OurName), NULL, 0, flags);
1130 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
1131 debuglog(2, "name resolution failure (local)");
1135 debuglog(1, "local socket is %s:%u", OurName,
1136 ntohs(server_iob.sa.sin_port));
1138 /* ignore SIGPIPE */
1139 bzero(&new_sa, sizeof(new_sa));
1140 new_sa.sa_handler = SIG_IGN;
1141 (void)sigemptyset(&new_sa.sa_mask);
1142 new_sa.sa_flags = SA_RESTART;
1143 if (sigaction(SIGPIPE, &new_sa, &old_sa) != 0) {
1144 syslog(LOG_ERR, "sigaction() failed (%m)");
1148 if (setsockopt(client_iob.fd, SOL_SOCKET, SO_OOBINLINE, (char *)&one,
1149 sizeof(one)) == -1) {
1150 syslog(LOG_NOTICE, "cannot set SO_OOBINLINE (%m)");
1154 client_iob.line_buffer_size = STARTBUFSIZE;
1155 client_iob.line_buffer = malloc(client_iob.line_buffer_size);
1156 client_iob.io_buffer_size = STARTBUFSIZE;
1157 client_iob.io_buffer = malloc(client_iob.io_buffer_size);
1158 client_iob.next_byte = 0;
1159 client_iob.io_buffer_len = 0;
1160 client_iob.alive = 1;
1161 client_iob.who = "client";
1162 client_iob.send_oob_flags = 0;
1163 client_iob.real_sa = client_iob.sa;
1165 server_iob.line_buffer_size = STARTBUFSIZE;
1166 server_iob.line_buffer = malloc(server_iob.line_buffer_size);
1167 server_iob.io_buffer_size = STARTBUFSIZE;
1168 server_iob.io_buffer = malloc(server_iob.io_buffer_size);
1169 server_iob.next_byte = 0;
1170 server_iob.io_buffer_len = 0;
1171 server_iob.alive = 1;
1172 server_iob.who = "server";
1173 server_iob.send_oob_flags = MSG_OOB;
1174 server_iob.real_sa = real_server_sa;
1176 if (client_iob.line_buffer == NULL || client_iob.io_buffer == NULL ||
1177 server_iob.line_buffer == NULL || server_iob.io_buffer == NULL) {
1178 syslog (LOG_NOTICE, "insufficient memory");
1179 exit(EX_UNAVAILABLE);
1182 while (client_iob.alive || server_iob.alive) {
1186 if (client_iob.fd > maxfd)
1187 maxfd = client_iob.fd;
1188 if (client_listen_socket > maxfd)
1189 maxfd = client_listen_socket;
1190 if (client_data_socket > maxfd)
1191 maxfd = client_data_socket;
1192 if (server_iob.fd > maxfd)
1193 maxfd = server_iob.fd;
1194 if (server_listen_socket > maxfd)
1195 maxfd = server_listen_socket;
1196 if (server_data_socket > maxfd)
1197 maxfd = server_data_socket;
1199 debuglog(3, "client is %s; server is %s",
1200 client_iob.alive ? "alive" : "dead",
1201 server_iob.alive ? "alive" : "dead");
1203 fdsp = (fd_set *)calloc(howmany(maxfd + 1, NFDBITS),
1206 syslog(LOG_NOTICE, "insufficient memory");
1207 exit(EX_UNAVAILABLE);
1210 if (client_iob.alive && telnet_getline(&client_iob,
1212 debuglog(3, "client line buffer is \"%s\"",
1213 (char *)client_iob.line_buffer);
1214 if (client_iob.line_buffer[0] != '\0')
1215 do_client_cmd(&client_iob, &server_iob);
1216 } else if (server_iob.alive && telnet_getline(&server_iob,
1218 debuglog(3, "server line buffer is \"%s\"",
1219 (char *)server_iob.line_buffer);
1220 if (server_iob.line_buffer[0] != '\0')
1221 do_server_reply(&server_iob, &client_iob);
1223 if (client_iob.alive) {
1224 FD_SET(client_iob.fd, fdsp);
1225 if (client_listen_socket >= 0)
1226 FD_SET(client_listen_socket, fdsp);
1227 if (client_data_socket >= 0)
1228 FD_SET(client_data_socket, fdsp);
1230 if (server_iob.alive) {
1231 FD_SET(server_iob.fd, fdsp);
1232 if (server_listen_socket >= 0)
1233 FD_SET(server_listen_socket, fdsp);
1234 if (server_data_socket >= 0)
1235 FD_SET(server_data_socket, fdsp);
1237 tv.tv_sec = timeout_seconds;
1241 sval = select(maxfd + 1, fdsp, NULL, NULL,
1242 (tv.tv_sec == 0) ? NULL : &tv);
1245 * This proxy has timed out. Expire it
1246 * quietly with an obituary in the syslogs
1247 * for any passing mourners.
1250 "timeout: no data for %ld seconds",
1255 if (errno == EINTR || errno == EAGAIN)
1258 "select() failed (%m)");
1261 if (client_data_socket >= 0 &&
1262 FD_ISSET(client_data_socket, fdsp)) {
1265 debuglog(3, "transfer: client to server");
1266 rval = xfer_data("client to server",
1268 server_data_socket);
1270 close_client_data();
1271 close_server_data();
1274 client_data_bytes += rval;
1276 if (server_data_socket >= 0 &&
1277 FD_ISSET(server_data_socket, fdsp)) {
1280 debuglog(3, "transfer: server to client");
1281 rval = xfer_data("server to client",
1283 client_data_socket);
1285 close_client_data();
1286 close_server_data();
1289 server_data_bytes += rval;
1291 if (server_listen_socket >= 0 &&
1292 FD_ISSET(server_listen_socket, fdsp)) {
1293 connect_port_backchannel();
1295 if (client_listen_socket >= 0 &&
1296 FD_ISSET(client_listen_socket, fdsp)) {
1297 connect_pasv_backchannel();
1299 if (client_iob.alive &&
1300 FD_ISSET(client_iob.fd, fdsp)) {
1301 client_iob.data_available = 1;
1303 if (server_iob.alive &&
1304 FD_ISSET(server_iob.fd, fdsp)) {
1305 server_iob.data_available = 1;
1309 if (client_iob.got_eof) {
1310 shutdown(server_iob.fd, 1);
1311 shutdown(client_iob.fd, 0);
1312 client_iob.got_eof = 0;
1313 client_iob.alive = 0;
1315 if (server_iob.got_eof) {
1316 shutdown(client_iob.fd, 1);
1317 shutdown(server_iob.fd, 0);
1318 server_iob.got_eof = 0;
1319 server_iob.alive = 0;
1324 syslog(LOG_INFO, "session ended");