1 /* $OpenBSD: ftp-proxy.c,v 1.38 2004/11/19 00:47:23 jmc Exp $ */
2 /* $DragonFly: src/libexec/ftp-proxy/ftp-proxy.c,v 1.2 2005/02/24 15:38:09 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
;
132 struct sockaddr_in proxy_sa
;
133 struct in_addr src_addr
;
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
;
146 char ClientName
[NI_MAXHOST
];
147 char RealServerName
[NI_MAXHOST
];
148 char OurName
[NI_MAXHOST
];
150 const char *User
= "proxy";
153 extern int Debug_Level
;
155 extern in_addr_t Bind_Addr
;
156 extern char *__progname
;
166 connection_mode_t connection_mode
;
168 extern void debuglog(int debug_level
, const char *fmt
, ...);
169 double wallclock_time(void);
170 void show_xfer_stats(void);
171 void log_control_command (char *cmd
, int client
);
172 int new_dataconn(int server
);
173 void do_client_cmd(struct csiob
*client
, struct csiob
*server
);
174 void do_server_reply(struct csiob
*server
, struct csiob
*client
);
179 "usage: %s [-AnrVw] [-a address] [-D debuglevel] [-g group]"
180 " [-M maxport] [-m minport] [-R address[:port]] [-S address]"
181 " [-t timeout] [-u user]", __progname
);
186 close_client_data(void)
188 if (client_data_socket
>= 0) {
189 shutdown(client_data_socket
, 2);
190 close(client_data_socket
);
191 client_data_socket
= -1;
196 close_server_data(void)
198 if (server_data_socket
>= 0) {
199 shutdown(server_data_socket
, 2);
200 close(server_data_socket
);
201 server_data_socket
= -1;
216 syslog(LOG_ERR
, "cannot find user %s", User
);
224 gr
= getgrnam(Group
);
226 syslog(LOG_ERR
, "cannot find group %s", Group
);
232 if (gid
!= 0 && (setegid(gid
) == -1 || setgid(gid
) == -1)) {
233 syslog(LOG_ERR
, "cannot drop group privs (%m)");
237 if (uid
!= 0 && (seteuid(uid
) == -1 || setuid(uid
) == -1)) {
238 syslog(LOG_ERR
, "cannot drop root privs (%m)");
245 * Check a connection against the tcpwrapper, log if we're going to
246 * reject it, returns: 0 -> reject, 1 -> accept. We add in hostnames
247 * if we are set to do reverse DNS, otherwise no.
250 check_host(struct sockaddr_in
*client_sin
, struct sockaddr_in
*server_sin
)
252 char cname
[NI_MAXHOST
];
253 char sname
[NI_MAXHOST
];
254 struct request_info request
;
257 request_init(&request
, RQ_DAEMON
, __progname
, RQ_CLIENT_SIN
,
258 client_sin
, RQ_SERVER_SIN
, server_sin
, RQ_CLIENT_ADDR
,
259 inet_ntoa(client_sin
->sin_addr
), 0);
263 * We already looked these up, but we have to do it again
264 * for tcp wrapper, to ensure that we get the DNS name, since
265 * the tcp wrapper cares about these things, and we don't
266 * want to pass in a printed address as a name.
268 i
= getnameinfo((struct sockaddr
*) &client_sin
->sin_addr
,
269 sizeof(&client_sin
->sin_addr
), cname
, sizeof(cname
),
270 NULL
, 0, NI_NAMEREQD
);
272 if (i
!= 0 && i
!= EAI_NONAME
&& i
!= EAI_AGAIN
)
273 strlcpy(cname
, STRING_UNKNOWN
, sizeof(cname
));
275 i
= getnameinfo((struct sockaddr
*)&server_sin
->sin_addr
,
276 sizeof(&server_sin
->sin_addr
), sname
, sizeof(sname
),
277 NULL
, 0, NI_NAMEREQD
);
279 if (i
!= 0 && i
!= EAI_NONAME
&& i
!= EAI_AGAIN
)
280 strlcpy(sname
, STRING_UNKNOWN
, sizeof(sname
));
283 * ensure the TCP wrapper doesn't start doing
284 * reverse DNS lookups if we aren't supposed to.
286 strlcpy(cname
, STRING_UNKNOWN
, sizeof(cname
));
287 strlcpy(sname
, STRING_UNKNOWN
, sizeof(sname
));
290 request_set(&request
, RQ_SERVER_ADDR
, inet_ntoa(server_sin
->sin_addr
),
292 request_set(&request
, RQ_CLIENT_NAME
, cname
, RQ_SERVER_NAME
, sname
, 0);
294 if (!hosts_access(&request
)) {
295 syslog(LOG_NOTICE
, "tcpwrappers rejected: %s -> %s",
296 ClientName
, RealServerName
);
308 gettimeofday(&tv
, NULL
);
309 return(tv
.tv_sec
+ tv
.tv_usec
/ 1e6
);
313 * Show the stats for this data transfer
316 show_xfer_stats(void)
326 delta
= wallclock_time() - xfer_start_time
;
331 if (client_data_bytes
== 0 && server_data_bytes
== 0) {
333 "data transfer complete (no bytes transferred)");
342 idelta
= delta
+ 0.5;
343 if (idelta
>= 60*60) {
344 i
= snprintf(tbuf
, len
,
345 "data transfer complete (%dh %dm %ds",
346 idelta
/ (60*60), (idelta
% (60*60)) / 60,
352 i
= snprintf(tbuf
, len
,
353 "data transfer complete (%dm %ds", idelta
/ 60,
360 i
= snprintf(tbuf
, len
, "data transfer complete (%.1fs",
367 if (client_data_bytes
> 0) {
368 i
= snprintf(&tbuf
[strlen(tbuf
)], len
,
369 ", %d bytes to server) (%.1fKB/s", client_data_bytes
,
370 (client_data_bytes
/ delta
) / (double)1024);
375 if (server_data_bytes
> 0) {
376 i
= snprintf(&tbuf
[strlen(tbuf
)], len
,
377 ", %d bytes to client) (%.1fKB/s", server_data_bytes
,
378 (server_data_bytes
/ delta
) / (double)1024);
383 strlcat(tbuf
, ")", sizeof(tbuf
));
385 syslog(LOG_INFO
, "%s", tbuf
);
389 log_control_command (char *cmd
, int client
)
391 /* log an ftp control command or reply */
392 const char *logstring
;
393 int level
= LOG_DEBUG
;
398 /* don't log passwords */
399 if (strncasecmp(cmd
, "pass ", 5) == 0)
400 logstring
= "PASS XXXX";
404 /* log interesting stuff at LOG_INFO, rest at LOG_DEBUG */
405 if ((strncasecmp(cmd
, "user ", 5) == 0) ||
406 (strncasecmp(cmd
, "retr ", 5) == 0) ||
407 (strncasecmp(cmd
, "cwd ", 4) == 0) ||
408 (strncasecmp(cmd
, "stor " ,5) == 0))
411 syslog(level
, "%s %s", client
? "client:" : " server:",
416 * set ourselves up for a new data connection. Direction is toward client if
417 * "server" is 0, towards server otherwise.
420 new_dataconn(int server
)
423 * Close existing data conn.
426 if (client_listen_socket
!= -1) {
427 close(client_listen_socket
);
428 client_listen_socket
= -1;
432 if (server_listen_socket
!= -1) {
433 close(server_listen_socket
);
434 server_listen_socket
= -1;
439 bzero(&server_listen_sa
, sizeof(server_listen_sa
));
440 server_listen_socket
= get_backchannel_socket(SOCK_STREAM
,
441 min_port
, max_port
, -1, 1, &server_listen_sa
);
443 if (server_listen_socket
== -1) {
444 syslog(LOG_INFO
, "server socket bind() failed (%m)");
447 if (listen(server_listen_socket
, 5) != 0) {
448 syslog(LOG_INFO
, "server socket listen() failed (%m)");
452 bzero(&client_listen_sa
, sizeof(client_listen_sa
));
453 client_listen_socket
= get_backchannel_socket(SOCK_STREAM
,
454 min_port
, max_port
, -1, 1, &client_listen_sa
);
456 if (client_listen_socket
== -1) {
458 "cannot get client listen socket (%m)");
461 if (listen(client_listen_socket
, 5) != 0) {
463 "cannot listen on client socket (%m)");
471 connect_pasv_backchannel(void)
473 struct sockaddr_in listen_sa
;
477 * We are about to accept a connection from the client.
478 * This is a PASV data connection.
480 debuglog(2, "client listen socket ready");
485 salen
= sizeof(listen_sa
);
486 client_data_socket
= accept(client_listen_socket
,
487 (struct sockaddr
*)&listen_sa
, &salen
);
489 if (client_data_socket
< 0) {
490 syslog(LOG_NOTICE
, "accept() failed (%m)");
493 close(client_listen_socket
);
494 client_listen_socket
= -1;
495 memset(&listen_sa
, 0, sizeof(listen_sa
));
497 server_data_socket
= get_backchannel_socket(SOCK_STREAM
, min_port
,
498 max_port
, -1, 1, &listen_sa
);
499 if (server_data_socket
< 0) {
500 syslog(LOG_NOTICE
, "get_backchannel_socket() failed (%m)");
503 if (connect(server_data_socket
, (struct sockaddr
*) &server_listen_sa
,
504 sizeof(server_listen_sa
)) != 0) {
505 syslog(LOG_NOTICE
, "connect() failed (%m)");
508 client_data_bytes
= 0;
509 server_data_bytes
= 0;
510 xfer_start_time
= wallclock_time();
514 connect_port_backchannel(void)
516 struct sockaddr_in listen_sa
;
520 * We are about to accept a connection from the server.
521 * This is a PORT or EPRT data connection.
523 debuglog(2, "server listen socket ready");
528 salen
= sizeof(listen_sa
);
529 server_data_socket
= accept(server_listen_socket
,
530 (struct sockaddr
*)&listen_sa
, &salen
);
531 if (server_data_socket
< 0) {
532 syslog(LOG_NOTICE
, "accept() failed (%m)");
535 close(server_listen_socket
);
536 server_listen_socket
= -1;
540 * We're not running as root, so we get a backchannel
541 * socket bound in our designated range, instead of
542 * getting one bound to port 20 - This is deliberately
545 bcopy(&src_addr
, &listen_sa
.sin_addr
, sizeof(struct in_addr
));
546 client_data_socket
= get_backchannel_socket(SOCK_STREAM
,
547 min_port
, max_port
, -1, 1, &listen_sa
);
548 if (client_data_socket
< 0) {
549 syslog(LOG_NOTICE
, "get_backchannel_socket() failed (%m)");
556 * We're root, get our backchannel socket bound to port
557 * 20 here, so we're fully RFC compliant.
559 client_data_socket
= socket(AF_INET
, SOCK_STREAM
, 0);
562 listen_sa
.sin_family
= AF_INET
;
563 bcopy(&src_addr
, &listen_sa
.sin_addr
, sizeof(struct in_addr
));
564 listen_sa
.sin_port
= htons(20);
566 if (setsockopt(client_data_socket
, SOL_SOCKET
, SO_REUSEADDR
,
567 &salen
, sizeof(salen
)) == -1) {
568 syslog(LOG_NOTICE
, "setsockopt() failed (%m)");
572 if (bind(client_data_socket
, (struct sockaddr
*)&listen_sa
,
573 sizeof(listen_sa
)) == - 1) {
574 syslog(LOG_NOTICE
, "data channel bind() failed (%m)");
579 if (connect(client_data_socket
, (struct sockaddr
*) &client_listen_sa
,
580 sizeof(client_listen_sa
)) != 0) {
581 syslog(LOG_INFO
, "cannot connect data channel (%m)");
585 client_data_bytes
= 0;
586 server_data_bytes
= 0;
587 xfer_start_time
= wallclock_time();
591 do_client_cmd(struct csiob
*client
, struct csiob
*server
)
595 char *sendbuf
= NULL
;
597 log_control_command((char *)client
->line_buffer
, 1);
599 /* client->line_buffer is an ftp control command.
600 * There is no reason for these to be very long.
601 * In the interest of limiting buffer overrun attempts,
602 * we catch them here.
604 if (strlen((char *)client
->line_buffer
) > 512) {
605 syslog(LOG_NOTICE
, "excessively long control command");
610 * Check the client user provided if needed
612 if (AnonFtpOnly
&& strncasecmp((char *)client
->line_buffer
, "user ",
613 strlen("user ")) == 0) {
616 cp
= (char *) client
->line_buffer
+ strlen("user ");
617 if ((strcasecmp(cp
, "ftp\r\n") != 0) &&
618 (strcasecmp(cp
, "anonymous\r\n") != 0)) {
620 * this isn't anonymous - give the client an
621 * error before they send a password
623 snprintf(tbuf
, sizeof(tbuf
),
624 "500 Only anonymous FTP is allowed\r\n");
628 rv
= send(client
->fd
, tbuf
+ j
, i
- j
, 0);
629 if (rv
== -1 && errno
!= EAGAIN
&&
634 } while (j
>= 0 && j
< i
);
637 sendbuf
= (char *)client
->line_buffer
;
638 } else if ((strncasecmp((char *)client
->line_buffer
, "eprt ",
639 strlen("eprt ")) == 0)) {
641 /* Watch out for EPRT commands */
642 char *line
= NULL
, *q
, *p
, *result
[3], delim
;
643 struct addrinfo hints
, *res
= NULL
;
647 line
= strdup((char *)client
->line_buffer
+strlen("eprt "));
649 syslog(LOG_ERR
, "insufficient memory");
650 exit(EX_UNAVAILABLE
);
656 memset(result
,0, sizeof(result
));
657 for (i
= 0; i
< 3; i
++) {
658 q
= strchr(p
, delim
);
659 if (!q
|| *q
!= delim
)
666 proto
= strtoul(result
[0], &p
, 10);
667 if (!*result
[0] || *p
)
670 memset(&hints
, 0, sizeof(hints
));
671 if (proto
!= 1) /* 1 == AF_INET - all we support for now */
673 hints
.ai_family
= AF_INET
;
674 hints
.ai_socktype
= SOCK_STREAM
;
675 hints
.ai_flags
= AI_NUMERICHOST
; /*no DNS*/
676 if (getaddrinfo(result
[1], result
[2], &hints
, &res
))
680 if (sizeof(client_listen_sa
) < res
->ai_addrlen
)
682 memcpy(&client_listen_sa
, res
->ai_addr
, res
->ai_addrlen
);
684 debuglog(1, "client wants us to use %s:%u",
685 inet_ntoa(client_listen_sa
.sin_addr
),
686 htons(client_listen_sa
.sin_port
));
689 * Configure our own listen socket and tell the server about it
692 connection_mode
= EPRT_MODE
;
694 debuglog(1, "we want server to use %s:%u",
695 inet_ntoa(server
->sa
.sin_addr
),
696 ntohs(server_listen_sa
.sin_port
));
698 snprintf(tbuf
, sizeof(tbuf
), "EPRT |%d|%s|%u|\r\n", 1,
699 inet_ntoa(server
->sa
.sin_addr
),
700 ntohs(server_listen_sa
.sin_port
));
701 debuglog(1, "to server (modified): %s", tbuf
);
705 snprintf(tbuf
, sizeof(tbuf
),
706 "500 Invalid argument; rejected\r\n");
710 /* we only support AF_INET for now */
712 snprintf(tbuf
, sizeof(tbuf
),
713 "522 Protocol not supported, use (1)\r\n");
715 snprintf(tbuf
, sizeof(tbuf
),
716 "501 Protocol not supported\r\n");
723 if (sendbuf
== NULL
) {
724 debuglog(1, "to client (modified): %s", tbuf
);
727 rv
= send(client
->fd
, tbuf
+ j
, i
- j
, 0);
728 if (rv
== -1 && errno
!= EAGAIN
&&
733 } while (j
>= 0 && j
< i
);
735 } else if (!NatMode
&& (strncasecmp((char *)client
->line_buffer
,
736 "epsv", strlen("epsv")) == 0)) {
739 * If we aren't in NAT mode, deal with EPSV.
740 * EPSV is a problem - Unlike PASV, the reply from the
741 * server contains *only* a port, we can't modify the reply
742 * to the client and get the client to connect to us without
743 * resorting to using a dynamic rdr rule we have to add in
744 * for the reply to this connection, and take away afterwards.
745 * so this will wait until we have the right solution for rule
746 * additions/deletions in pf.
748 * in the meantime we just tell the client we don't do it,
749 * and most clients should fall back to using PASV.
752 snprintf(tbuf
, sizeof(tbuf
),
753 "500 EPSV command not understood\r\n");
754 debuglog(1, "to client (modified): %s", tbuf
);
758 rv
= send(client
->fd
, tbuf
+ j
, i
- j
, 0);
759 if (rv
== -1 && errno
!= EAGAIN
&& errno
!= EINTR
)
763 } while (j
>= 0 && j
< i
);
765 } else if (strncasecmp((char *)client
->line_buffer
, "port ",
766 strlen("port ")) == 0) {
767 unsigned int values
[6];
770 debuglog(1, "Got a PORT command");
772 tailptr
= (char *)&client
->line_buffer
[strlen("port ")];
775 i
= sscanf(tailptr
, "%u,%u,%u,%u,%u,%u", &values
[0],
776 &values
[1], &values
[2], &values
[3], &values
[4],
779 syslog(LOG_INFO
, "malformed PORT command (%s)",
780 client
->line_buffer
);
784 for (i
= 0; i
<6; i
++) {
785 if (values
[i
] > 255) {
787 "malformed PORT command (%s)",
788 client
->line_buffer
);
793 client_listen_sa
.sin_family
= AF_INET
;
794 client_listen_sa
.sin_addr
.s_addr
= htonl((values
[0] << 24) |
795 (values
[1] << 16) | (values
[2] << 8) |
798 client_listen_sa
.sin_port
= htons((values
[4] << 8) |
800 debuglog(1, "client wants us to use %u.%u.%u.%u:%u",
801 values
[0], values
[1], values
[2], values
[3],
802 (values
[4] << 8) | values
[5]);
805 * Configure our own listen socket and tell the server about it
808 connection_mode
= PORT_MODE
;
810 debuglog(1, "we want server to use %s:%u",
811 inet_ntoa(server
->sa
.sin_addr
),
812 ntohs(server_listen_sa
.sin_port
));
814 snprintf(tbuf
, sizeof(tbuf
), "PORT %u,%u,%u,%u,%u,%u\r\n",
815 ((u_char
*)&server
->sa
.sin_addr
.s_addr
)[0],
816 ((u_char
*)&server
->sa
.sin_addr
.s_addr
)[1],
817 ((u_char
*)&server
->sa
.sin_addr
.s_addr
)[2],
818 ((u_char
*)&server
->sa
.sin_addr
.s_addr
)[3],
819 ((u_char
*)&server_listen_sa
.sin_port
)[0],
820 ((u_char
*)&server_listen_sa
.sin_port
)[1]);
822 debuglog(1, "to server (modified): %s", tbuf
);
826 sendbuf
= (char *)client
->line_buffer
;
829 *send our (possibly modified) control command in sendbuf
830 * on it's way to the server
832 if (sendbuf
!= NULL
) {
836 rv
= send(server
->fd
, sendbuf
+ j
, i
- j
, 0);
837 if (rv
== -1 && errno
!= EAGAIN
&& errno
!= EINTR
)
841 } while (j
>= 0 && j
< i
);
846 do_server_reply(struct csiob
*server
, struct csiob
*client
)
850 static int continuing
= 0;
851 char tbuf
[100], *sendbuf
, *p
;
853 log_control_command((char *)server
->line_buffer
, 0);
855 if (strlen((char *)server
->line_buffer
) > 512) {
857 * someone's playing games. Have a cow in the syslogs and
858 * exit - we don't pass this on for fear of hurting
859 * our other end, which might be poorly implemented.
861 syslog(LOG_NOTICE
, "long FTP control reply");
866 * Watch out for "227 Entering Passive Mode ..." replies
868 code
= strtol((char *)server
->line_buffer
, &p
, 10);
869 if (isspace(server
->line_buffer
[0]))
871 if (!*(server
->line_buffer
) || (*p
!= ' ' && *p
!= '-')) {
874 syslog(LOG_INFO
, "malformed control reply");
877 if (code
<= 0 || code
> 999) {
880 syslog(LOG_INFO
, "invalid server reply code %d", code
);
887 if (code
== 227 && !NatMode
) {
888 unsigned int values
[6];
891 debuglog(1, "Got a PASV reply");
892 debuglog(1, "{%s}", (char *)server
->line_buffer
);
894 tailptr
= (char *)strchr((char *)server
->line_buffer
, '(');
895 if (tailptr
== NULL
) {
896 tailptr
= strrchr((char *)server
->line_buffer
, ' ');
897 if (tailptr
== NULL
) {
898 syslog(LOG_NOTICE
, "malformed 227 reply");
902 tailptr
++; /* skip past space or ( */
906 i
= sscanf(tailptr
, "%u,%u,%u,%u,%u,%u", &values
[0],
907 &values
[1], &values
[2], &values
[3], &values
[4],
910 syslog(LOG_INFO
, "malformed PASV reply (%s)",
911 client
->line_buffer
);
914 for (i
= 0; i
<6; i
++)
915 if (values
[i
] > 255) {
916 syslog(LOG_INFO
, "malformed PASV reply(%s)",
917 client
->line_buffer
);
921 server_listen_sa
.sin_family
= AF_INET
;
922 server_listen_sa
.sin_addr
.s_addr
= htonl((values
[0] << 24) |
923 (values
[1] << 16) | (values
[2] << 8) | (values
[3] << 0));
924 server_listen_sa
.sin_port
= htons((values
[4] << 8) |
927 debuglog(1, "server wants us to use %s:%u",
928 inet_ntoa(server_listen_sa
.sin_addr
), (values
[4] << 8) |
932 connection_mode
= PASV_MODE
;
934 iap
= &(proxy_sa
.sin_addr
);
936 iap
= &(server
->sa
.sin_addr
);
938 debuglog(1, "we want client to use %s:%u", inet_ntoa(*iap
),
939 htons(client_listen_sa
.sin_port
));
941 snprintf(tbuf
, sizeof(tbuf
),
942 "227 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n",
943 ((u_char
*)iap
)[0], ((u_char
*)iap
)[1],
944 ((u_char
*)iap
)[2], ((u_char
*)iap
)[3],
945 ((u_char
*)&client_listen_sa
.sin_port
)[0],
946 ((u_char
*)&client_listen_sa
.sin_port
)[1]);
947 debuglog(1, "to client (modified): %s", tbuf
);
951 sendbuf
= (char *)server
->line_buffer
;
955 * send our (possibly modified) control command in sendbuf
956 * on it's way to the client
961 rv
= send(client
->fd
, sendbuf
+ j
, i
- j
, 0);
962 if (rv
== -1 && errno
!= EAGAIN
&& errno
!= EINTR
)
966 } while (j
>= 0 && j
< i
);
971 main(int argc
, char *argv
[])
973 struct csiob client_iob
, server_iob
;
974 struct sigaction new_sa
, old_sa
;
975 int sval
, ch
, flags
, i
;
978 long timeout_seconds
= 0;
981 int use_tcpwrapper
= 0;
984 while ((ch
= getopt(argc
, argv
, "a:D:g:m:M:R:S:t:u:AnVwr")) != -1) {
990 if ((Bind_Addr
= inet_addr(optarg
)) == INADDR_NONE
) {
992 "%s: invalid address", optarg
);
997 AnonFtpOnly
= 1; /* restrict to anon usernames only */
1000 Debug_Level
= strtol(optarg
, &p
, 10);
1008 min_port
= strtol(optarg
, &p
, 10);
1011 if (min_port
< 0 || min_port
> USHRT_MAX
)
1015 max_port
= strtol(optarg
, &p
, 10);
1018 if (max_port
< 0 || max_port
> USHRT_MAX
)
1022 NatMode
= 1; /* pass all passives, we're using NAT */
1025 Use_Rdns
= 1; /* look up hostnames */
1032 if ((s
= strdup(optarg
)) == NULL
) {
1034 "Insufficient memory (malloc failed)");
1035 exit(EX_UNAVAILABLE
);
1037 memset(&real_server_sa
, 0, sizeof(real_server_sa
));
1038 real_server_sa
.sin_len
= sizeof(struct sockaddr_in
);
1039 real_server_sa
.sin_family
= AF_INET
;
1042 real_server_sa
.sin_port
= htons(21);
1044 long port
= strtol(t
+ 1, &p
, 10);
1046 if (*p
|| port
<= 0 || port
> 65535)
1048 real_server_sa
.sin_port
= htons(port
);
1051 real_server_sa
.sin_addr
.s_addr
= inet_addr(s
);
1052 if (real_server_sa
.sin_addr
.s_addr
== INADDR_NONE
)
1059 if (!inet_aton(optarg
, &src_addr
))
1063 timeout_seconds
= strtol(optarg
, &p
, 10);
1075 use_tcpwrapper
= 1; /* do the libwrap thing */
1077 #endif /* LIBWRAP */
1086 if (max_port
< min_port
)
1089 openlog(__progname
, LOG_NDELAY
|LOG_PID
, LOG_DAEMON
);
1094 memset(&client_iob
, 0, sizeof(client_iob
));
1095 memset(&server_iob
, 0, sizeof(server_iob
));
1097 if (get_proxy_env(0, &real_server_sa
, &client_iob
.sa
,
1102 * We may now drop root privs, as we have done our ioctl for
1103 * pf. If we do drop root, we can't make backchannel connections
1104 * for PORT and EPRT come from port 20, which is not strictly
1105 * RFC compliant. This shouldn't cause problems for all but
1106 * the stupidest ftp clients and the stupidest packet filters.
1111 * We check_host after get_proxy_env so that checks are done
1112 * against the original destination endpoint, not the endpoint
1113 * of our side of the rdr. This allows the use of tcpwrapper
1114 * rules to restrict destinations as well as sources of connections
1120 flags
= NI_NUMERICHOST
| NI_NUMERICSERV
;
1122 i
= getnameinfo((struct sockaddr
*)&client_iob
.sa
,
1123 sizeof(client_iob
.sa
), ClientName
, sizeof(ClientName
), NULL
, 0,
1126 if (i
!= 0 && i
!= EAI_NONAME
&& i
!= EAI_AGAIN
) {
1127 debuglog(2, "name resolution failure (client)");
1131 i
= getnameinfo((struct sockaddr
*)&real_server_sa
,
1132 sizeof(real_server_sa
), RealServerName
, sizeof(RealServerName
),
1135 if (i
!= 0 && i
!= EAI_NONAME
&& i
!= EAI_AGAIN
) {
1136 debuglog(2, "name resolution failure (server)");
1141 if (use_tcpwrapper
&& !check_host(&client_iob
.sa
, &real_server_sa
))
1147 syslog(LOG_INFO
, "accepted connection from %s:%u to %s:%u", ClientName
,
1148 ntohs(client_iob
.sa
.sin_port
), RealServerName
,
1149 ntohs(real_server_sa
.sin_port
));
1151 server_iob
.fd
= get_backchannel_socket(SOCK_STREAM
, min_port
, max_port
,
1152 -1, 1, &server_iob
.sa
);
1154 if (connect(server_iob
.fd
, (struct sockaddr
*)&real_server_sa
,
1155 sizeof(real_server_sa
)) != 0) {
1156 syslog(LOG_INFO
, "cannot connect to %s:%u (%m)", RealServerName
,
1157 ntohs(real_server_sa
.sin_port
));
1162 * Now that we are connected to the real server, get the name
1163 * of our end of the server socket so we know our IP address
1164 * from the real server's perspective.
1166 salen
= sizeof(server_iob
.sa
);
1167 getsockname(server_iob
.fd
, (struct sockaddr
*)&server_iob
.sa
, &salen
);
1169 i
= getnameinfo((struct sockaddr
*)&server_iob
.sa
,
1170 sizeof(server_iob
.sa
), OurName
, sizeof(OurName
), NULL
, 0, flags
);
1172 if (i
!= 0 && i
!= EAI_NONAME
&& i
!= EAI_AGAIN
) {
1173 debuglog(2, "name resolution failure (local)");
1177 debuglog(1, "local socket is %s:%u", OurName
,
1178 ntohs(server_iob
.sa
.sin_port
));
1180 /* ignore SIGPIPE */
1181 bzero(&new_sa
, sizeof(new_sa
));
1182 new_sa
.sa_handler
= SIG_IGN
;
1183 (void)sigemptyset(&new_sa
.sa_mask
);
1184 new_sa
.sa_flags
= SA_RESTART
;
1185 if (sigaction(SIGPIPE
, &new_sa
, &old_sa
) != 0) {
1186 syslog(LOG_ERR
, "sigaction() failed (%m)");
1190 if (setsockopt(client_iob
.fd
, SOL_SOCKET
, SO_OOBINLINE
, (char *)&one
,
1191 sizeof(one
)) == -1) {
1192 syslog(LOG_NOTICE
, "cannot set SO_OOBINLINE (%m)");
1196 client_iob
.line_buffer_size
= STARTBUFSIZE
;
1197 client_iob
.line_buffer
= malloc(client_iob
.line_buffer_size
);
1198 client_iob
.io_buffer_size
= STARTBUFSIZE
;
1199 client_iob
.io_buffer
= malloc(client_iob
.io_buffer_size
);
1200 client_iob
.next_byte
= 0;
1201 client_iob
.io_buffer_len
= 0;
1202 client_iob
.alive
= 1;
1203 client_iob
.who
= "client";
1204 client_iob
.send_oob_flags
= 0;
1205 client_iob
.real_sa
= client_iob
.sa
;
1207 server_iob
.line_buffer_size
= STARTBUFSIZE
;
1208 server_iob
.line_buffer
= malloc(server_iob
.line_buffer_size
);
1209 server_iob
.io_buffer_size
= STARTBUFSIZE
;
1210 server_iob
.io_buffer
= malloc(server_iob
.io_buffer_size
);
1211 server_iob
.next_byte
= 0;
1212 server_iob
.io_buffer_len
= 0;
1213 server_iob
.alive
= 1;
1214 server_iob
.who
= "server";
1215 server_iob
.send_oob_flags
= MSG_OOB
;
1216 server_iob
.real_sa
= real_server_sa
;
1218 if (client_iob
.line_buffer
== NULL
|| client_iob
.io_buffer
== NULL
||
1219 server_iob
.line_buffer
== NULL
|| server_iob
.io_buffer
== NULL
) {
1220 syslog (LOG_NOTICE
, "insufficient memory");
1221 exit(EX_UNAVAILABLE
);
1224 while (client_iob
.alive
|| server_iob
.alive
) {
1228 if (client_iob
.fd
> maxfd
)
1229 maxfd
= client_iob
.fd
;
1230 if (client_listen_socket
> maxfd
)
1231 maxfd
= client_listen_socket
;
1232 if (client_data_socket
> maxfd
)
1233 maxfd
= client_data_socket
;
1234 if (server_iob
.fd
> maxfd
)
1235 maxfd
= server_iob
.fd
;
1236 if (server_listen_socket
> maxfd
)
1237 maxfd
= server_listen_socket
;
1238 if (server_data_socket
> maxfd
)
1239 maxfd
= server_data_socket
;
1241 debuglog(3, "client is %s; server is %s",
1242 client_iob
.alive
? "alive" : "dead",
1243 server_iob
.alive
? "alive" : "dead");
1245 fdsp
= (fd_set
*)calloc(howmany(maxfd
+ 1, NFDBITS
),
1248 syslog(LOG_NOTICE
, "insufficient memory");
1249 exit(EX_UNAVAILABLE
);
1252 if (client_iob
.alive
&& telnet_getline(&client_iob
,
1254 debuglog(3, "client line buffer is \"%s\"",
1255 (char *)client_iob
.line_buffer
);
1256 if (client_iob
.line_buffer
[0] != '\0')
1257 do_client_cmd(&client_iob
, &server_iob
);
1258 } else if (server_iob
.alive
&& telnet_getline(&server_iob
,
1260 debuglog(3, "server line buffer is \"%s\"",
1261 (char *)server_iob
.line_buffer
);
1262 if (server_iob
.line_buffer
[0] != '\0')
1263 do_server_reply(&server_iob
, &client_iob
);
1265 if (client_iob
.alive
) {
1266 FD_SET(client_iob
.fd
, fdsp
);
1267 if (client_listen_socket
>= 0)
1268 FD_SET(client_listen_socket
, fdsp
);
1269 if (client_data_socket
>= 0)
1270 FD_SET(client_data_socket
, fdsp
);
1272 if (server_iob
.alive
) {
1273 FD_SET(server_iob
.fd
, fdsp
);
1274 if (server_listen_socket
>= 0)
1275 FD_SET(server_listen_socket
, fdsp
);
1276 if (server_data_socket
>= 0)
1277 FD_SET(server_data_socket
, fdsp
);
1279 tv
.tv_sec
= timeout_seconds
;
1283 sval
= select(maxfd
+ 1, fdsp
, NULL
, NULL
,
1284 (tv
.tv_sec
== 0) ? NULL
: &tv
);
1287 * This proxy has timed out. Expire it
1288 * quietly with an obituary in the syslogs
1289 * for any passing mourners.
1292 "timeout: no data for %ld seconds",
1297 if (errno
== EINTR
|| errno
== EAGAIN
)
1300 "select() failed (%m)");
1303 if (client_data_socket
>= 0 &&
1304 FD_ISSET(client_data_socket
, fdsp
)) {
1307 debuglog(3, "transfer: client to server");
1308 rval
= xfer_data("client to server",
1311 client_iob
.sa
.sin_addr
,
1312 real_server_sa
.sin_addr
);
1314 close_client_data();
1315 close_server_data();
1318 client_data_bytes
+= rval
;
1320 if (server_data_socket
>= 0 &&
1321 FD_ISSET(server_data_socket
, fdsp
)) {
1324 debuglog(3, "transfer: server to client");
1325 rval
= xfer_data("server to client",
1328 real_server_sa
.sin_addr
,
1329 client_iob
.sa
.sin_addr
);
1331 close_client_data();
1332 close_server_data();
1335 server_data_bytes
+= rval
;
1337 if (server_listen_socket
>= 0 &&
1338 FD_ISSET(server_listen_socket
, fdsp
)) {
1339 connect_port_backchannel();
1341 if (client_listen_socket
>= 0 &&
1342 FD_ISSET(client_listen_socket
, fdsp
)) {
1343 connect_pasv_backchannel();
1345 if (client_iob
.alive
&&
1346 FD_ISSET(client_iob
.fd
, fdsp
)) {
1347 client_iob
.data_available
= 1;
1349 if (server_iob
.alive
&&
1350 FD_ISSET(server_iob
.fd
, fdsp
)) {
1351 server_iob
.data_available
= 1;
1355 if (client_iob
.got_eof
) {
1356 shutdown(server_iob
.fd
, 1);
1357 shutdown(client_iob
.fd
, 0);
1358 client_iob
.got_eof
= 0;
1359 client_iob
.alive
= 0;
1361 if (server_iob
.got_eof
) {
1362 shutdown(client_iob
.fd
, 1);
1363 shutdown(server_iob
.fd
, 0);
1364 server_iob
.got_eof
= 0;
1365 server_iob
.alive
= 0;
1370 syslog(LOG_INFO
, "session ended");