1 /* $OpenBSD: ftp-proxy.c,v 1.35 2004/03/14 21:51:44 dhartmei 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;
135 int client_listen_socket = -1; /* Only used in PASV mode */
136 int client_data_socket = -1; /* Connected socket to real client */
137 int server_listen_socket = -1; /* Only used in PORT mode */
138 int server_data_socket = -1; /* Connected socket to real server */
139 int client_data_bytes, server_data_bytes;
145 char ClientName[NI_MAXHOST];
146 char RealServerName[NI_MAXHOST];
147 char OurName[NI_MAXHOST];
149 char *User = "proxy";
152 extern int Debug_Level;
154 extern in_addr_t Bind_Addr;
155 extern char *__progname;
165 connection_mode_t connection_mode;
167 extern void debuglog(int debug_level, const char *fmt, ...);
168 double wallclock_time(void);
169 void show_xfer_stats(void);
170 void log_control_command (char *cmd, int client);
171 int new_dataconn(int server);
172 void do_client_cmd(struct csiob *client, struct csiob *server);
173 void do_server_reply(struct csiob *server, struct csiob *client);
178 "usage: %s [-AnrVw] [-a address] [-D debuglevel [-g group]"
179 " [-M maxport] [-m minport] [-t timeout] [-u user]", __progname);
184 close_client_data(void)
186 if (client_data_socket >= 0) {
187 shutdown(client_data_socket, 2);
188 close(client_data_socket);
189 client_data_socket = -1;
194 close_server_data(void)
196 if (server_data_socket >= 0) {
197 shutdown(server_data_socket, 2);
198 close(server_data_socket);
199 server_data_socket = -1;
214 syslog(LOG_ERR, "cannot find user %s", User);
222 gr = getgrnam(Group);
224 syslog(LOG_ERR, "cannot find group %s", Group);
230 if (gid != 0 && (setegid(gid) == -1 || setgid(gid) == -1)) {
231 syslog(LOG_ERR, "cannot drop group privs (%m)");
235 if (uid != 0 && (seteuid(uid) == -1 || setuid(uid) == -1)) {
236 syslog(LOG_ERR, "cannot drop root privs (%m)");
243 * Check a connection against the tcpwrapper, log if we're going to
244 * reject it, returns: 0 -> reject, 1 -> accept. We add in hostnames
245 * if we are set to do reverse DNS, otherwise no.
248 check_host(struct sockaddr_in *client_sin, struct sockaddr_in *server_sin)
250 char cname[NI_MAXHOST];
251 char sname[NI_MAXHOST];
252 struct request_info request;
255 request_init(&request, RQ_DAEMON, __progname, RQ_CLIENT_SIN,
256 client_sin, RQ_SERVER_SIN, server_sin, RQ_CLIENT_ADDR,
257 inet_ntoa(client_sin->sin_addr), 0);
261 * We already looked these up, but we have to do it again
262 * for tcp wrapper, to ensure that we get the DNS name, since
263 * the tcp wrapper cares about these things, and we don't
264 * want to pass in a printed address as a name.
266 i = getnameinfo((struct sockaddr *) &client_sin->sin_addr,
267 sizeof(&client_sin->sin_addr), cname, sizeof(cname),
268 NULL, 0, NI_NAMEREQD);
270 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN)
271 strlcpy(cname, STRING_UNKNOWN, sizeof(cname));
273 i = getnameinfo((struct sockaddr *)&server_sin->sin_addr,
274 sizeof(&server_sin->sin_addr), sname, sizeof(sname),
275 NULL, 0, NI_NAMEREQD);
277 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN)
278 strlcpy(sname, STRING_UNKNOWN, sizeof(sname));
281 * ensure the TCP wrapper doesn't start doing
282 * reverse DNS lookups if we aren't supposed to.
284 strlcpy(cname, STRING_UNKNOWN, sizeof(cname));
285 strlcpy(sname, STRING_UNKNOWN, sizeof(sname));
288 request_set(&request, RQ_SERVER_ADDR, inet_ntoa(server_sin->sin_addr),
290 request_set(&request, RQ_CLIENT_NAME, cname, RQ_SERVER_NAME, sname, 0);
292 if (!hosts_access(&request)) {
293 syslog(LOG_NOTICE, "tcpwrappers rejected: %s -> %s",
294 ClientName, RealServerName);
306 gettimeofday(&tv, NULL);
307 return(tv.tv_sec + tv.tv_usec / 1e6);
311 * Show the stats for this data transfer
314 show_xfer_stats(void)
324 delta = wallclock_time() - xfer_start_time;
329 if (client_data_bytes == 0 && server_data_bytes == 0) {
331 "data transfer complete (no bytes transferred)");
340 idelta = delta + 0.5;
341 if (idelta >= 60*60) {
342 i = snprintf(tbuf, len,
343 "data transfer complete (%dh %dm %ds",
344 idelta / (60*60), (idelta % (60*60)) / 60,
350 i = snprintf(tbuf, len,
351 "data transfer complete (%dm %ds", idelta / 60,
358 i = snprintf(tbuf, len, "data transfer complete (%.1fs",
365 if (client_data_bytes > 0) {
366 i = snprintf(&tbuf[strlen(tbuf)], len,
367 ", %d bytes to server) (%.1fKB/s", client_data_bytes,
368 (client_data_bytes / delta) / (double)1024);
373 if (server_data_bytes > 0) {
374 i = snprintf(&tbuf[strlen(tbuf)], len,
375 ", %d bytes to client) (%.1fKB/s", server_data_bytes,
376 (server_data_bytes / delta) / (double)1024);
381 strlcat(tbuf, ")", sizeof(tbuf));
383 syslog(LOG_INFO, "%s", tbuf);
387 log_control_command (char *cmd, int client)
389 /* log an ftp control command or reply */
391 int level = LOG_DEBUG;
396 /* don't log passwords */
397 if (strncasecmp(cmd, "pass ", 5) == 0)
398 logstring = "PASS XXXX";
402 /* log interesting stuff at LOG_INFO, rest at LOG_DEBUG */
403 if ((strncasecmp(cmd, "user ", 5) == 0) ||
404 (strncasecmp(cmd, "retr ", 5) == 0) ||
405 (strncasecmp(cmd, "cwd ", 4) == 0) ||
406 (strncasecmp(cmd, "stor " ,5) == 0))
409 syslog(level, "%s %s", client ? "client:" : " server:",
414 * set ourselves up for a new data connection. Direction is toward client if
415 * "server" is 0, towards server otherwise.
418 new_dataconn(int server)
421 * Close existing data conn.
424 if (client_listen_socket != -1) {
425 close(client_listen_socket);
426 client_listen_socket = -1;
430 if (server_listen_socket != -1) {
431 close(server_listen_socket);
432 server_listen_socket = -1;
437 bzero(&server_listen_sa, sizeof(server_listen_sa));
438 server_listen_socket = get_backchannel_socket(SOCK_STREAM,
439 min_port, max_port, -1, 1, &server_listen_sa);
441 if (server_listen_socket == -1) {
442 syslog(LOG_INFO, "server socket bind() failed (%m)");
445 if (listen(server_listen_socket, 5) != 0) {
446 syslog(LOG_INFO, "server socket listen() failed (%m)");
450 bzero(&client_listen_sa, sizeof(client_listen_sa));
451 client_listen_socket = get_backchannel_socket(SOCK_STREAM,
452 min_port, max_port, -1, 1, &client_listen_sa);
454 if (client_listen_socket == -1) {
456 "cannot get client listen socket (%m)");
459 if (listen(client_listen_socket, 5) != 0) {
461 "cannot listen on client socket (%m)");
469 connect_pasv_backchannel(void)
471 struct sockaddr_in listen_sa;
475 * We are about to accept a connection from the client.
476 * This is a PASV data connection.
478 debuglog(2, "client listen socket ready");
483 salen = sizeof(listen_sa);
484 client_data_socket = accept(client_listen_socket,
485 (struct sockaddr *)&listen_sa, &salen);
487 if (client_data_socket < 0) {
488 syslog(LOG_NOTICE, "accept() failed (%m)");
491 close(client_listen_socket);
492 client_listen_socket = -1;
493 memset(&listen_sa, 0, sizeof(listen_sa));
495 server_data_socket = get_backchannel_socket(SOCK_STREAM, min_port,
496 max_port, -1, 1, &listen_sa);
497 if (server_data_socket < 0) {
498 syslog(LOG_NOTICE, "get_backchannel_socket() failed (%m)");
501 if (connect(server_data_socket, (struct sockaddr *) &server_listen_sa,
502 sizeof(server_listen_sa)) != 0) {
503 syslog(LOG_NOTICE, "connect() failed (%m)");
506 client_data_bytes = 0;
507 server_data_bytes = 0;
508 xfer_start_time = wallclock_time();
512 connect_port_backchannel(void)
514 struct sockaddr_in listen_sa;
518 * We are about to accept a connection from the server.
519 * This is a PORT or EPRT data connection.
521 debuglog(2, "server listen socket ready");
526 salen = sizeof(listen_sa);
527 server_data_socket = accept(server_listen_socket,
528 (struct sockaddr *)&listen_sa, &salen);
529 if (server_data_socket < 0) {
530 syslog(LOG_NOTICE, "accept() failed (%m)");
533 close(server_listen_socket);
534 server_listen_socket = -1;
538 * We're not running as root, so we get a backchannel
539 * socket bound in our designated range, instead of
540 * getting one bound to port 20 - This is deliberately
543 bzero(&listen_sa.sin_addr, sizeof(struct in_addr));
544 client_data_socket = get_backchannel_socket(SOCK_STREAM,
545 min_port, max_port, -1, 1, &listen_sa);
546 if (client_data_socket < 0) {
547 syslog(LOG_NOTICE, "get_backchannel_socket() failed (%m)");
554 * We're root, get our backchannel socket bound to port
555 * 20 here, so we're fully RFC compliant.
557 client_data_socket = socket(AF_INET, SOCK_STREAM, 0);
560 listen_sa.sin_family = AF_INET;
561 bzero(&listen_sa.sin_addr, sizeof(struct in_addr));
562 listen_sa.sin_port = htons(20);
564 if (setsockopt(client_data_socket, SOL_SOCKET, SO_REUSEADDR,
565 &salen, sizeof(salen)) == -1) {
566 syslog(LOG_NOTICE, "setsockopt() failed (%m)");
570 if (bind(client_data_socket, (struct sockaddr *)&listen_sa,
571 sizeof(listen_sa)) == - 1) {
572 syslog(LOG_NOTICE, "data channel bind() failed (%m)");
577 if (connect(client_data_socket, (struct sockaddr *) &client_listen_sa,
578 sizeof(client_listen_sa)) != 0) {
579 syslog(LOG_INFO, "cannot connect data channel (%m)");
583 client_data_bytes = 0;
584 server_data_bytes = 0;
585 xfer_start_time = wallclock_time();
589 do_client_cmd(struct csiob *client, struct csiob *server)
593 char *sendbuf = NULL;
595 log_control_command((char *)client->line_buffer, 1);
597 /* client->line_buffer is an ftp control command.
598 * There is no reason for these to be very long.
599 * In the interest of limiting buffer overrun attempts,
600 * we catch them here.
602 if (strlen((char *)client->line_buffer) > 512) {
603 syslog(LOG_NOTICE, "excessively long control command");
608 * Check the client user provided if needed
610 if (AnonFtpOnly && strncasecmp((char *)client->line_buffer, "user ",
611 strlen("user ")) == 0) {
614 cp = (char *) client->line_buffer + strlen("user ");
615 if ((strcasecmp(cp, "ftp\r\n") != 0) &&
616 (strcasecmp(cp, "anonymous\r\n") != 0)) {
618 * this isn't anonymous - give the client an
619 * error before they send a password
621 snprintf(tbuf, sizeof(tbuf),
622 "500 Only anonymous FTP is allowed\r\n");
626 rv = send(client->fd, tbuf + j, i - j, 0);
627 if (rv == -1 && errno != EAGAIN &&
632 } while (j >= 0 && j < i);
635 sendbuf = (char *)client->line_buffer;
636 } else if ((strncasecmp((char *)client->line_buffer, "eprt ",
637 strlen("eprt ")) == 0)) {
639 /* Watch out for EPRT commands */
640 char *line = NULL, *q, *p, *result[3], delim;
641 struct addrinfo hints, *res = NULL;
645 line = strdup((char *)client->line_buffer+strlen("eprt "));
647 syslog(LOG_ERR, "insufficient memory");
648 exit(EX_UNAVAILABLE);
654 memset(result,0, sizeof(result));
655 for (i = 0; i < 3; i++) {
656 q = strchr(p, delim);
657 if (!q || *q != delim)
664 proto = strtoul(result[0], &p, 10);
665 if (!*result[0] || *p)
668 memset(&hints, 0, sizeof(hints));
669 if (proto != 1) /* 1 == AF_INET - all we support for now */
671 hints.ai_family = AF_INET;
672 hints.ai_socktype = SOCK_STREAM;
673 hints.ai_flags = AI_NUMERICHOST; /*no DNS*/
674 if (getaddrinfo(result[1], result[2], &hints, &res))
678 if (sizeof(client_listen_sa) < res->ai_addrlen)
680 memcpy(&client_listen_sa, res->ai_addr, res->ai_addrlen);
682 debuglog(1, "client wants us to use %s:%u",
683 inet_ntoa(client_listen_sa.sin_addr),
684 htons(client_listen_sa.sin_port));
687 * Configure our own listen socket and tell the server about it
690 connection_mode = EPRT_MODE;
692 debuglog(1, "we want server to use %s:%u",
693 inet_ntoa(server->sa.sin_addr),
694 ntohs(server_listen_sa.sin_port));
696 snprintf(tbuf, sizeof(tbuf), "EPRT |%d|%s|%u|\r\n", 1,
697 inet_ntoa(server->sa.sin_addr),
698 ntohs(server_listen_sa.sin_port));
699 debuglog(1, "to server (modified): %s", tbuf);
703 snprintf(tbuf, sizeof(tbuf),
704 "500 Invalid argument; rejected\r\n");
708 /* we only support AF_INET for now */
710 snprintf(tbuf, sizeof(tbuf),
711 "522 Protocol not supported, use (1)\r\n");
713 snprintf(tbuf, sizeof(tbuf),
714 "501 Protocol not supported\r\n");
721 if (sendbuf == NULL) {
722 debuglog(1, "to client (modified): %s", tbuf);
725 rv = send(client->fd, tbuf + j, i - j, 0);
726 if (rv == -1 && errno != EAGAIN &&
731 } while (j >= 0 && j < i);
733 } else if (!NatMode && (strncasecmp((char *)client->line_buffer,
734 "epsv", strlen("epsv")) == 0)) {
737 * If we aren't in NAT mode, deal with EPSV.
738 * EPSV is a problem - Unlike PASV, the reply from the
739 * server contains *only* a port, we can't modify the reply
740 * to the client and get the client to connect to us without
741 * resorting to using a dynamic rdr rule we have to add in
742 * for the reply to this connection, and take away afterwards.
743 * so this will wait until we have the right solution for rule
744 * additions/deletions in pf.
746 * in the meantime we just tell the client we don't do it,
747 * and most clients should fall back to using PASV.
750 snprintf(tbuf, sizeof(tbuf),
751 "500 EPSV command not understood\r\n");
752 debuglog(1, "to client (modified): %s", tbuf);
756 rv = send(client->fd, tbuf + j, i - j, 0);
757 if (rv == -1 && errno != EAGAIN && errno != EINTR)
761 } while (j >= 0 && j < i);
763 } else if (strncasecmp((char *)client->line_buffer, "port ",
764 strlen("port ")) == 0) {
765 unsigned int values[6];
768 debuglog(1, "Got a PORT command");
770 tailptr = (char *)&client->line_buffer[strlen("port ")];
773 i = sscanf(tailptr, "%u,%u,%u,%u,%u,%u", &values[0],
774 &values[1], &values[2], &values[3], &values[4],
777 syslog(LOG_INFO, "malformed PORT command (%s)",
778 client->line_buffer);
782 for (i = 0; i<6; i++) {
783 if (values[i] > 255) {
785 "malformed PORT command (%s)",
786 client->line_buffer);
791 client_listen_sa.sin_family = AF_INET;
792 client_listen_sa.sin_addr.s_addr = htonl((values[0] << 24) |
793 (values[1] << 16) | (values[2] << 8) |
796 client_listen_sa.sin_port = htons((values[4] << 8) |
798 debuglog(1, "client wants us to use %u.%u.%u.%u:%u",
799 values[0], values[1], values[2], values[3],
800 (values[4] << 8) | values[5]);
803 * Configure our own listen socket and tell the server about it
806 connection_mode = PORT_MODE;
808 debuglog(1, "we want server to use %s:%u",
809 inet_ntoa(server->sa.sin_addr),
810 ntohs(server_listen_sa.sin_port));
812 snprintf(tbuf, sizeof(tbuf), "PORT %u,%u,%u,%u,%u,%u\r\n",
813 ((u_char *)&server->sa.sin_addr.s_addr)[0],
814 ((u_char *)&server->sa.sin_addr.s_addr)[1],
815 ((u_char *)&server->sa.sin_addr.s_addr)[2],
816 ((u_char *)&server->sa.sin_addr.s_addr)[3],
817 ((u_char *)&server_listen_sa.sin_port)[0],
818 ((u_char *)&server_listen_sa.sin_port)[1]);
820 debuglog(1, "to server (modified): %s", tbuf);
824 sendbuf = (char *)client->line_buffer;
827 *send our (possibly modified) control command in sendbuf
828 * on it's way to the server
830 if (sendbuf != NULL) {
834 rv = send(server->fd, sendbuf + j, i - j, 0);
835 if (rv == -1 && errno != EAGAIN && errno != EINTR)
839 } while (j >= 0 && j < i);
844 do_server_reply(struct csiob *server, struct csiob *client)
848 static int continuing = 0;
849 char tbuf[100], *sendbuf, *p;
851 log_control_command((char *)server->line_buffer, 0);
853 if (strlen((char *)server->line_buffer) > 512) {
855 * someone's playing games. Have a cow in the syslogs and
856 * exit - we don't pass this on for fear of hurting
857 * our other end, which might be poorly implemented.
859 syslog(LOG_NOTICE, "long FTP control reply");
864 * Watch out for "227 Entering Passive Mode ..." replies
866 code = strtol((char *)server->line_buffer, &p, 10);
867 if (isspace(server->line_buffer[0]))
869 if (!*(server->line_buffer) || (*p != ' ' && *p != '-')) {
872 syslog(LOG_INFO, "malformed control reply");
875 if (code <= 0 || code > 999) {
878 syslog(LOG_INFO, "invalid server reply code %d", code);
885 if (code == 227 && !NatMode) {
886 unsigned int values[6];
889 debuglog(1, "Got a PASV reply");
890 debuglog(1, "{%s}", (char *)server->line_buffer);
892 tailptr = (char *)strchr((char *)server->line_buffer, '(');
893 if (tailptr == NULL) {
894 tailptr = strrchr((char *)server->line_buffer, ' ');
895 if (tailptr == NULL) {
896 syslog(LOG_NOTICE, "malformed 227 reply");
900 tailptr++; /* skip past space or ( */
904 i = sscanf(tailptr, "%u,%u,%u,%u,%u,%u", &values[0],
905 &values[1], &values[2], &values[3], &values[4],
908 syslog(LOG_INFO, "malformed PASV reply (%s)",
909 client->line_buffer);
912 for (i = 0; i<6; i++)
913 if (values[i] > 255) {
914 syslog(LOG_INFO, "malformed PASV reply(%s)",
915 client->line_buffer);
919 server_listen_sa.sin_family = AF_INET;
920 server_listen_sa.sin_addr.s_addr = htonl((values[0] << 24) |
921 (values[1] << 16) | (values[2] << 8) | (values[3] << 0));
922 server_listen_sa.sin_port = htons((values[4] << 8) |
925 debuglog(1, "server wants us to use %s:%u",
926 inet_ntoa(server_listen_sa.sin_addr), (values[4] << 8) |
930 connection_mode = PASV_MODE;
931 iap = &(server->sa.sin_addr);
933 debuglog(1, "we want client to use %s:%u", inet_ntoa(*iap),
934 htons(client_listen_sa.sin_port));
936 snprintf(tbuf, sizeof(tbuf),
937 "227 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n",
938 ((u_char *)iap)[0], ((u_char *)iap)[1],
939 ((u_char *)iap)[2], ((u_char *)iap)[3],
940 ((u_char *)&client_listen_sa.sin_port)[0],
941 ((u_char *)&client_listen_sa.sin_port)[1]);
942 debuglog(1, "to client (modified): %s", tbuf);
946 sendbuf = (char *)server->line_buffer;
950 * send our (possibly modified) control command in sendbuf
951 * on it's way to the client
956 rv = send(client->fd, sendbuf + j, i - j, 0);
957 if (rv == -1 && errno != EAGAIN && errno != EINTR)
961 } while (j >= 0 && j < i);
966 main(int argc, char *argv[])
968 struct csiob client_iob, server_iob;
969 struct sigaction new_sa, old_sa;
970 int sval, ch, flags, i;
973 long timeout_seconds = 0;
976 int use_tcpwrapper = 0;
979 while ((ch = getopt(argc, argv, "a:D:g:m:M:t:u:AnVwr")) != -1) {
985 if ((Bind_Addr = inet_addr(optarg)) == INADDR_NONE) {
987 "%s: invalid address", optarg);
992 AnonFtpOnly = 1; /* restrict to anon usernames only */
995 Debug_Level = strtol(optarg, &p, 10);
1003 min_port = strtol(optarg, &p, 10);
1006 if (min_port < 0 || min_port > USHRT_MAX)
1010 max_port = strtol(optarg, &p, 10);
1013 if (max_port < 0 || max_port > USHRT_MAX)
1017 NatMode = 1; /* pass all passives, we're using NAT */
1020 Use_Rdns = 1; /* look up hostnames */
1023 timeout_seconds = strtol(optarg, &p, 10);
1035 use_tcpwrapper = 1; /* do the libwrap thing */
1037 #endif /* LIBWRAP */
1046 if (max_port < min_port)
1049 openlog(__progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
1054 memset(&client_iob, 0, sizeof(client_iob));
1055 memset(&server_iob, 0, sizeof(server_iob));
1057 if (get_proxy_env(0, &real_server_sa, &client_iob.sa) == -1)
1061 * We may now drop root privs, as we have done our ioctl for
1062 * pf. If we do drop root, we can't make backchannel connections
1063 * for PORT and EPRT come from port 20, which is not strictly
1064 * RFC compliant. This shouldn't cause problems for all but
1065 * the stupidest ftp clients and the stupidest packet filters.
1070 * We check_host after get_proxy_env so that checks are done
1071 * against the original destination endpoint, not the endpoint
1072 * of our side of the rdr. This allows the use of tcpwrapper
1073 * rules to restrict destinations as well as sources of connections
1079 flags = NI_NUMERICHOST | NI_NUMERICSERV;
1081 i = getnameinfo((struct sockaddr *)&client_iob.sa,
1082 sizeof(client_iob.sa), ClientName, sizeof(ClientName), NULL, 0,
1085 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
1086 debuglog(2, "name resolution failure (client)");
1090 i = getnameinfo((struct sockaddr *)&real_server_sa,
1091 sizeof(real_server_sa), RealServerName, sizeof(RealServerName),
1094 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
1095 debuglog(2, "name resolution failure (server)");
1100 if (use_tcpwrapper && !check_host(&client_iob.sa, &real_server_sa))
1106 syslog(LOG_INFO, "accepted connection from %s:%u to %s:%u", ClientName,
1107 ntohs(client_iob.sa.sin_port), RealServerName,
1108 ntohs(real_server_sa.sin_port));
1110 server_iob.fd = get_backchannel_socket(SOCK_STREAM, min_port, max_port,
1111 -1, 1, &server_iob.sa);
1113 if (connect(server_iob.fd, (struct sockaddr *)&real_server_sa,
1114 sizeof(real_server_sa)) != 0) {
1115 syslog(LOG_INFO, "cannot connect to %s:%u (%m)", RealServerName,
1116 ntohs(real_server_sa.sin_port));
1121 * Now that we are connected to the real server, get the name
1122 * of our end of the server socket so we know our IP address
1123 * from the real server's perspective.
1125 salen = sizeof(server_iob.sa);
1126 getsockname(server_iob.fd, (struct sockaddr *)&server_iob.sa, &salen);
1128 i = getnameinfo((struct sockaddr *)&server_iob.sa,
1129 sizeof(server_iob.sa), OurName, sizeof(OurName), NULL, 0, flags);
1131 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
1132 debuglog(2, "name resolution failure (local)");
1136 debuglog(1, "local socket is %s:%u", OurName,
1137 ntohs(server_iob.sa.sin_port));
1139 /* ignore SIGPIPE */
1140 bzero(&new_sa, sizeof(new_sa));
1141 new_sa.sa_handler = SIG_IGN;
1142 (void)sigemptyset(&new_sa.sa_mask);
1143 new_sa.sa_flags = SA_RESTART;
1144 if (sigaction(SIGPIPE, &new_sa, &old_sa) != 0) {
1145 syslog(LOG_ERR, "sigaction() failed (%m)");
1149 if (setsockopt(client_iob.fd, SOL_SOCKET, SO_OOBINLINE, (char *)&one,
1150 sizeof(one)) == -1) {
1151 syslog(LOG_NOTICE, "cannot set SO_OOBINLINE (%m)");
1155 client_iob.line_buffer_size = STARTBUFSIZE;
1156 client_iob.line_buffer = malloc(client_iob.line_buffer_size);
1157 client_iob.io_buffer_size = STARTBUFSIZE;
1158 client_iob.io_buffer = malloc(client_iob.io_buffer_size);
1159 client_iob.next_byte = 0;
1160 client_iob.io_buffer_len = 0;
1161 client_iob.alive = 1;
1162 client_iob.who = "client";
1163 client_iob.send_oob_flags = 0;
1164 client_iob.real_sa = client_iob.sa;
1166 server_iob.line_buffer_size = STARTBUFSIZE;
1167 server_iob.line_buffer = malloc(server_iob.line_buffer_size);
1168 server_iob.io_buffer_size = STARTBUFSIZE;
1169 server_iob.io_buffer = malloc(server_iob.io_buffer_size);
1170 server_iob.next_byte = 0;
1171 server_iob.io_buffer_len = 0;
1172 server_iob.alive = 1;
1173 server_iob.who = "server";
1174 server_iob.send_oob_flags = MSG_OOB;
1175 server_iob.real_sa = real_server_sa;
1177 if (client_iob.line_buffer == NULL || client_iob.io_buffer == NULL ||
1178 server_iob.line_buffer == NULL || server_iob.io_buffer == NULL) {
1179 syslog (LOG_NOTICE, "insufficient memory");
1180 exit(EX_UNAVAILABLE);
1183 while (client_iob.alive || server_iob.alive) {
1187 if (client_iob.fd > maxfd)
1188 maxfd = client_iob.fd;
1189 if (client_listen_socket > maxfd)
1190 maxfd = client_listen_socket;
1191 if (client_data_socket > maxfd)
1192 maxfd = client_data_socket;
1193 if (server_iob.fd > maxfd)
1194 maxfd = server_iob.fd;
1195 if (server_listen_socket > maxfd)
1196 maxfd = server_listen_socket;
1197 if (server_data_socket > maxfd)
1198 maxfd = server_data_socket;
1200 debuglog(3, "client is %s; server is %s",
1201 client_iob.alive ? "alive" : "dead",
1202 server_iob.alive ? "alive" : "dead");
1204 fdsp = (fd_set *)calloc(howmany(maxfd + 1, NFDBITS),
1207 syslog(LOG_NOTICE, "insufficient memory");
1208 exit(EX_UNAVAILABLE);
1211 if (client_iob.alive && telnet_getline(&client_iob,
1213 debuglog(3, "client line buffer is \"%s\"",
1214 (char *)client_iob.line_buffer);
1215 if (client_iob.line_buffer[0] != '\0')
1216 do_client_cmd(&client_iob, &server_iob);
1217 } else if (server_iob.alive && telnet_getline(&server_iob,
1219 debuglog(3, "server line buffer is \"%s\"",
1220 (char *)server_iob.line_buffer);
1221 if (server_iob.line_buffer[0] != '\0')
1222 do_server_reply(&server_iob, &client_iob);
1224 if (client_iob.alive) {
1225 FD_SET(client_iob.fd, fdsp);
1226 if (client_listen_socket >= 0)
1227 FD_SET(client_listen_socket, fdsp);
1228 if (client_data_socket >= 0)
1229 FD_SET(client_data_socket, fdsp);
1231 if (server_iob.alive) {
1232 FD_SET(server_iob.fd, fdsp);
1233 if (server_listen_socket >= 0)
1234 FD_SET(server_listen_socket, fdsp);
1235 if (server_data_socket >= 0)
1236 FD_SET(server_data_socket, fdsp);
1238 tv.tv_sec = timeout_seconds;
1242 sval = select(maxfd + 1, fdsp, NULL, NULL,
1243 (tv.tv_sec == 0) ? NULL : &tv);
1246 * This proxy has timed out. Expire it
1247 * quietly with an obituary in the syslogs
1248 * for any passing mourners.
1251 "timeout: no data for %ld seconds",
1256 if (errno == EINTR || errno == EAGAIN)
1259 "select() failed (%m)");
1262 if (client_data_socket >= 0 &&
1263 FD_ISSET(client_data_socket, fdsp)) {
1266 debuglog(3, "transfer: client to server");
1267 rval = xfer_data("client to server",
1270 client_iob.sa.sin_addr,
1271 real_server_sa.sin_addr);
1273 close_client_data();
1274 close_server_data();
1277 client_data_bytes += rval;
1279 if (server_data_socket >= 0 &&
1280 FD_ISSET(server_data_socket, fdsp)) {
1283 debuglog(3, "transfer: server to client");
1284 rval = xfer_data("server to client",
1287 real_server_sa.sin_addr,
1288 client_iob.sa.sin_addr);
1290 close_client_data();
1291 close_server_data();
1294 server_data_bytes += rval;
1296 if (server_listen_socket >= 0 &&
1297 FD_ISSET(server_listen_socket, fdsp)) {
1298 connect_port_backchannel();
1300 if (client_listen_socket >= 0 &&
1301 FD_ISSET(client_listen_socket, fdsp)) {
1302 connect_pasv_backchannel();
1304 if (client_iob.alive &&
1305 FD_ISSET(client_iob.fd, fdsp)) {
1306 client_iob.data_available = 1;
1308 if (server_iob.alive &&
1309 FD_ISSET(server_iob.fd, fdsp)) {
1310 server_iob.data_available = 1;
1314 if (client_iob.got_eof) {
1315 shutdown(server_iob.fd, 1);
1316 shutdown(client_iob.fd, 0);
1317 client_iob.got_eof = 0;
1318 client_iob.alive = 0;
1320 if (server_iob.got_eof) {
1321 shutdown(client_iob.fd, 1);
1322 shutdown(server_iob.fd, 0);
1323 server_iob.got_eof = 0;
1324 server_iob.alive = 0;
1329 syslog(LOG_INFO, "session ended");