1/* $OpenBSD: ftp-proxy.c,v 1.41 2005/03/05 23:11:19 cloder Exp $ */
| 1/* $OpenBSD: ftp-proxy.c,v 1.13 2006/12/30 13:24:00 camield Exp $ */
|
2 3/*
| 2 3/*
|
4 * Copyright (c) 1996-2001 5 * Obtuse Systems Corporation. All rights reserved.
| 4 * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl>
|
6 *
| 5 *
|
7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 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.
| 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies.
|
18 *
| 9 *
|
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. 30 *
| 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
31 */ 32 33#include <sys/cdefs.h>
| 17 */ 18 19#include <sys/cdefs.h>
|
34__FBSDID("$FreeBSD: head/contrib/pf/ftp-proxy/ftp-proxy.c 145840 2005-05-03 16:55:20Z mlaier $");
| 20__FBSDID("$FreeBSD: head/contrib/pf/ftp-proxy/ftp-proxy.c 171172 2007-07-03 12:30:03Z mlaier $");
|
35
| 21
|
36/* 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> 40 * 41 * This version basically passes everything through unchanged except 42 * for the PORT and the * "227 Entering Passive Mode" reply. 43 * 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. 49 * 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. 56 * 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 60 * 61 */ 62 63/* 64 * TODO: 65 * Plenty, this is very basic, with the idea to get it in clean first. 66 * 67 * - IPv6 and EPASV support 68 * - Content filter support 69 * - filename filter support 70 * - per-user rules perhaps. 71 */ 72 73#include <sys/param.h>
| 22#include <sys/queue.h> 23#include <sys/types.h>
|
74#include <sys/time.h>
| 24#include <sys/time.h>
|
| 25#include <sys/resource.h>
|
75#include <sys/socket.h> 76 77#include <net/if.h>
| 26#include <sys/socket.h> 27 28#include <net/if.h>
|
| 29#include <net/pfvar.h>
|
78#include <netinet/in.h>
| 30#include <netinet/in.h>
|
79
| |
80#include <arpa/inet.h> 81
| 31#include <arpa/inet.h> 32
|
82#include <ctype.h>
| 33#include <err.h>
|
83#include <errno.h>
| 34#include <errno.h>
|
84#include <grp.h>
| 35#include <event.h> 36#include <fcntl.h>
|
85#include <netdb.h> 86#include <pwd.h> 87#include <signal.h> 88#include <stdarg.h> 89#include <stdio.h> 90#include <stdlib.h> 91#include <string.h>
| 37#include <netdb.h> 38#include <pwd.h> 39#include <signal.h> 40#include <stdarg.h> 41#include <stdio.h> 42#include <stdlib.h> 43#include <string.h>
|
92#include <sysexits.h>
| |
93#include <syslog.h> 94#include <unistd.h>
| 44#include <syslog.h> 45#include <unistd.h>
|
| 46#include <vis.h>
|
95
| 47
|
96#include "util.h"
| 48#include "filter.h"
|
97
| 49
|
98#ifdef LIBWRAP 99#include <tcpd.h> 100int allow_severity = LOG_INFO; 101int deny_severity = LOG_NOTICE; 102#endif /* LIBWRAP */
| 50#define CONNECT_TIMEOUT 30 51#define MIN_PORT 1024 52#define MAX_LINE 500 53#define MAX_LOGLINE 300 54#define NTOP_BUFS 3 55#define TCP_BACKLOG 10
|
103
| 56
|
104int min_port = IPPORT_HIFIRSTAUTO; 105int max_port = IPPORT_HILASTAUTO;
| 57#define CHROOT_DIR "/var/empty" 58#define NOPRIV_USER "proxy"
|
106
| 59
|
107#define STARTBUFSIZE 1024 /* Must be at least 3 */
| 60/* pfctl standard NAT range. */ 61#define PF_NAT_PROXY_PORT_LOW 50001 62#define PF_NAT_PROXY_PORT_HIGH 65535
|
108
| 63
|
109/* 110 * Variables used to support PORT mode connections. 111 * 112 * This gets a bit complicated. 113 * 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 117 * with us). 118 * 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 122 * listening on. 123 * 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. 127 */
| 64#define sstosa(ss) ((struct sockaddr *)(ss))
|
128
| 65
|
129double xfer_start_time;
| 66enum { CMD_NONE = 0, CMD_PORT, CMD_EPRT, CMD_PASV, CMD_EPSV };
|
130
| 67
|
131struct sockaddr_in real_server_sa; 132struct sockaddr_in client_listen_sa; 133struct sockaddr_in server_listen_sa; 134struct sockaddr_in proxy_sa; 135struct in_addr src_addr;
| 68struct session { 69 u_int32_t id; 70 struct sockaddr_storage client_ss; 71 struct sockaddr_storage proxy_ss; 72 struct sockaddr_storage server_ss; 73 struct sockaddr_storage orig_server_ss; 74 struct bufferevent *client_bufev; 75 struct bufferevent *server_bufev; 76 int client_fd; 77 int server_fd; 78 char cbuf[MAX_LINE]; 79 size_t cbuf_valid; 80 char sbuf[MAX_LINE]; 81 size_t sbuf_valid; 82 int cmd; 83 u_int16_t port; 84 u_int16_t proxy_port; 85 LIST_ENTRY(session) entry; 86};
|
136
| 87
|
137int client_listen_socket = -1; /* Only used in PASV mode */ 138int client_data_socket = -1; /* Connected socket to real client */ 139int server_listen_socket = -1; /* Only used in PORT mode */ 140int server_data_socket = -1; /* Connected socket to real server */ 141int client_data_bytes, server_data_bytes;
| 88LIST_HEAD(, session) sessions = LIST_HEAD_INITIALIZER(sessions);
|
142
| 89
|
143int AnonFtpOnly; 144int Verbose; 145int NatMode; 146int ReverseMode;
| 90void client_error(struct bufferevent *, short, void *); 91int client_parse(struct session *s); 92int client_parse_anon(struct session *s); 93int client_parse_cmd(struct session *s); 94void client_read(struct bufferevent *, void *); 95int drop_privs(void); 96void end_session(struct session *); 97int exit_daemon(void); 98int getline(char *, size_t *); 99void handle_connection(const int, short, void *); 100void handle_signal(int, short, void *); 101struct session * init_session(void); 102void logmsg(int, const char *, ...); 103u_int16_t parse_port(int); 104u_int16_t pick_proxy_port(void); 105void proxy_reply(int, struct sockaddr *, u_int16_t); 106void server_error(struct bufferevent *, short, void *); 107int server_parse(struct session *s); 108void server_read(struct bufferevent *, void *); 109const char *sock_ntop(struct sockaddr *); 110void usage(void);
|
147
| 111
|
148char ClientName[NI_MAXHOST]; 149char RealServerName[NI_MAXHOST]; 150char OurName[NI_MAXHOST];
| 112char linebuf[MAX_LINE + 1]; 113size_t linelen;
|
151
| 114
|
152const char *User = "proxy"; 153const char *Group;
| 115char ntop_buf[NTOP_BUFS][INET6_ADDRSTRLEN];
|
154
| 116
|
155extern int Debug_Level; 156extern int Use_Rdns; 157extern in_addr_t Bind_Addr;
| 117struct sockaddr_storage fixed_server_ss, fixed_proxy_ss; 118char *fixed_server, *fixed_server_port, *fixed_proxy, *listen_ip, *listen_port, 119 *qname; 120int anonymous_only, daemonize, id_count, ipv6_mode, loglevel, max_sessions, 121 rfc_mode, session_count, timeout, verbose;
|
158extern char *__progname; 159
| 122extern char *__progname; 123
|
160typedef enum { 161 UNKNOWN_MODE, 162 PORT_MODE, 163 PASV_MODE, 164 EPRT_MODE, 165 EPSV_MODE 166} connection_mode_t;
| 124void 125client_error(struct bufferevent *bufev, short what, void *arg) 126{ 127 struct session *s = arg;
|
167
| 128
|
168connection_mode_t connection_mode;
| 129 if (what & EVBUFFER_EOF) 130 logmsg(LOG_INFO, "#%d client close", s->id); 131 else if (what == (EVBUFFER_ERROR | EVBUFFER_READ)) 132 logmsg(LOG_ERR, "#%d client reset connection", s->id); 133 else if (what & EVBUFFER_TIMEOUT) 134 logmsg(LOG_ERR, "#%d client timeout", s->id); 135 else if (what & EVBUFFER_WRITE) 136 logmsg(LOG_ERR, "#%d client write error: %d", s->id, what); 137 else 138 logmsg(LOG_ERR, "#%d abnormal client error: %d", s->id, what);
|
169
| 139
|
170extern void debuglog(int debug_level, const char *fmt, ...); 171double wallclock_time(void); 172void show_xfer_stats(void); 173void log_control_command (char *cmd, int client); 174int new_dataconn(int server); 175void do_client_cmd(struct csiob *client, struct csiob *server); 176void do_server_reply(struct csiob *server, struct csiob *client); 177static void 178usage(void) 179{ 180 syslog(LOG_NOTICE, 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); 184 exit(EX_USAGE);
| 140 end_session(s);
|
185} 186
| 141} 142
|
187static void 188close_client_data(void)
| 143int 144client_parse(struct session *s)
|
189{
| 145{
|
190 if (client_data_socket >= 0) { 191 shutdown(client_data_socket, 2); 192 close(client_data_socket); 193 client_data_socket = -1; 194 }
| 146 /* Reset any previous command. */ 147 s->cmd = CMD_NONE; 148 s->port = 0; 149 150 /* Commands we are looking for are at least 4 chars long. */ 151 if (linelen < 4) 152 return (1); 153 154 if (linebuf[0] == 'P' || linebuf[0] == 'p' || 155 linebuf[0] == 'E' || linebuf[0] == 'e') 156 return (client_parse_cmd(s)); 157 158 if (anonymous_only && (linebuf[0] == 'U' || linebuf[0] == 'u')) 159 return (client_parse_anon(s)); 160 161 return (1);
|
195} 196
| 162} 163
|
197static void 198close_server_data(void)
| 164int 165client_parse_anon(struct session *s)
|
199{
| 166{
|
200 if (server_data_socket >= 0) { 201 shutdown(server_data_socket, 2); 202 close(server_data_socket); 203 server_data_socket = -1;
| 167 if (strcasecmp("USER ftp\r\n", linebuf) != 0 && 168 strcasecmp("USER anonymous\r\n", linebuf) != 0) { 169 snprintf(linebuf, sizeof linebuf, 170 "500 Only anonymous FTP allowed\r\n"); 171 logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, linebuf); 172 173 /* Talk back to the client ourself. */ 174 linelen = strlen(linebuf); 175 bufferevent_write(s->client_bufev, linebuf, linelen); 176 177 /* Clear buffer so it's not sent to the server. */ 178 linebuf[0] = '\0'; 179 linelen = 0;
|
204 }
| 180 }
|
| 181 182 return (1);
|
205} 206
| 183} 184
|
207static void 208drop_privs(void)
| 185int 186client_parse_cmd(struct session *s)
|
209{
| 187{
|
210 struct passwd *pw; 211 struct group *gr; 212 uid_t uid = 0; 213 gid_t gid = 0;
| 188 if (strncasecmp("PASV", linebuf, 4) == 0) 189 s->cmd = CMD_PASV; 190 else if (strncasecmp("PORT ", linebuf, 5) == 0) 191 s->cmd = CMD_PORT; 192 else if (strncasecmp("EPSV", linebuf, 4) == 0) 193 s->cmd = CMD_EPSV; 194 else if (strncasecmp("EPRT ", linebuf, 5) == 0) 195 s->cmd = CMD_EPRT; 196 else 197 return (1);
|
214
| 198
|
215 if (User != NULL) { 216 pw = getpwnam(User); 217 if (pw == NULL) { 218 syslog(LOG_ERR, "cannot find user %s", User); 219 exit(EX_USAGE); 220 } 221 uid = pw->pw_uid; 222 gid = pw->pw_gid;
| 199 if (ipv6_mode && (s->cmd == CMD_PASV || s->cmd == CMD_PORT)) { 200 logmsg(LOG_CRIT, "PASV and PORT not allowed with IPv6"); 201 return (0);
|
223 } 224
| 202 } 203
|
225 if (Group != NULL) { 226 gr = getgrnam(Group); 227 if (gr == NULL) { 228 syslog(LOG_ERR, "cannot find group %s", Group); 229 exit(EX_USAGE);
| 204 if (s->cmd == CMD_PORT || s->cmd == CMD_EPRT) { 205 s->port = parse_port(s->cmd); 206 if (s->port < MIN_PORT) { 207 logmsg(LOG_CRIT, "#%d bad port in '%s'", s->id, 208 linebuf); 209 return (0);
|
230 }
| 210 }
|
231 gid = gr->gr_gid;
| 211 s->proxy_port = pick_proxy_port(); 212 proxy_reply(s->cmd, sstosa(&s->proxy_ss), s->proxy_port); 213 logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, linebuf);
|
232 } 233
| 214 } 215
|
234 if (gid != 0 && (setegid(gid) == -1 || setgid(gid) == -1)) { 235 syslog(LOG_ERR, "cannot drop group privs (%m)"); 236 exit(EX_CONFIG); 237 } 238 239 if (uid != 0 && (seteuid(uid) == -1 || setuid(uid) == -1)) { 240 syslog(LOG_ERR, "cannot drop root privs (%m)"); 241 exit(EX_CONFIG); 242 }
| 216 return (1);
|
243} 244
| 217} 218
|
245#ifdef LIBWRAP 246/* 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. 250 */ 251static int 252check_host(struct sockaddr_in *client_sin, struct sockaddr_in *server_sin)
| 219void 220client_read(struct bufferevent *bufev, void *arg)
|
253{
| 221{
|
254 char cname[NI_MAXHOST]; 255 char sname[NI_MAXHOST]; 256 struct request_info request; 257 int i;
| 222 struct session *s = arg; 223 size_t buf_avail, read; 224 int n;
|
258
| 225
|
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);
| 226 do { 227 buf_avail = sizeof s->cbuf - s->cbuf_valid; 228 read = bufferevent_read(bufev, s->cbuf + s->cbuf_valid, 229 buf_avail); 230 s->cbuf_valid += read;
|
262
| 231
|
263 if (Use_Rdns) { 264 /* 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. 269 */ 270 i = getnameinfo((struct sockaddr *) &client_sin->sin_addr, 271 sizeof(&client_sin->sin_addr), cname, sizeof(cname), 272 NULL, 0, NI_NAMEREQD);
| 232 while ((n = getline(s->cbuf, &s->cbuf_valid)) > 0) { 233 logmsg(LOG_DEBUG, "#%d client: %s", s->id, linebuf); 234 if (!client_parse(s)) { 235 end_session(s); 236 return; 237 } 238 bufferevent_write(s->server_bufev, linebuf, linelen); 239 }
|
273
| 240
|
274 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) 275 strlcpy(cname, STRING_UNKNOWN, sizeof(cname));
| 241 if (n == -1) { 242 logmsg(LOG_ERR, "#%d client command too long or not" 243 " clean", s->id); 244 end_session(s); 245 return; 246 } 247 } while (read == buf_avail); 248}
|
276
| 249
|
277 i = getnameinfo((struct sockaddr *)&server_sin->sin_addr, 278 sizeof(&server_sin->sin_addr), sname, sizeof(sname), 279 NULL, 0, NI_NAMEREQD);
| 250int 251drop_privs(void) 252{ 253 struct passwd *pw;
|
280
| 254
|
281 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) 282 strlcpy(sname, STRING_UNKNOWN, sizeof(sname)); 283 } else { 284 /* 285 * ensure the TCP wrapper doesn't start doing 286 * reverse DNS lookups if we aren't supposed to. 287 */ 288 strlcpy(cname, STRING_UNKNOWN, sizeof(cname)); 289 strlcpy(sname, STRING_UNKNOWN, sizeof(sname)); 290 }
| 255 pw = getpwnam(NOPRIV_USER); 256 if (pw == NULL) 257 return (0);
|
291
| 258
|
292 request_set(&request, RQ_SERVER_ADDR, inet_ntoa(server_sin->sin_addr), 293 0); 294 request_set(&request, RQ_CLIENT_NAME, cname, RQ_SERVER_NAME, sname, 0);
| 259 tzset(); 260 if (chroot(CHROOT_DIR) != 0 || chdir("/") != 0 || 261 setgroups(1, &pw->pw_gid) != 0 || 262 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0 || 263 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) 264 return (0);
|
295
| 265
|
296 if (!hosts_access(&request)) { 297 syslog(LOG_NOTICE, "tcpwrappers rejected: %s -> %s", 298 ClientName, RealServerName); 299 return(0); 300 } 301 return(1);
| 266 return (1);
|
302}
| 267}
|
303#endif /* LIBWRAP */
| |
304
| 268
|
305double 306wallclock_time(void) 307{ 308 struct timeval tv; 309 310 gettimeofday(&tv, NULL); 311 return(tv.tv_sec + tv.tv_usec / 1e6); 312} 313 314/* 315 * Show the stats for this data transfer 316 */
| |
317void
| 269void
|
318show_xfer_stats(void)
| 270end_session(struct session *s)
|
319{
| 271{
|
320 char tbuf[1000]; 321 double delta; 322 size_t len; 323 int i = -1;
| 272 int err;
|
324
| 273
|
325 if (!Verbose) 326 return;
| 274 logmsg(LOG_INFO, "#%d ending session", s->id);
|
327
| 275
|
328 delta = wallclock_time() - xfer_start_time;
| 276 if (s->client_fd != -1) 277 close(s->client_fd); 278 if (s->server_fd != -1) 279 close(s->server_fd);
|
329
| 280
|
330 if (delta < 0.001) 331 delta = 0.001;
| 281 if (s->client_bufev) 282 bufferevent_free(s->client_bufev); 283 if (s->server_bufev) 284 bufferevent_free(s->server_bufev);
|
332
| 285
|
333 if (client_data_bytes == 0 && server_data_bytes == 0) { 334 syslog(LOG_INFO, 335 "data transfer complete (no bytes transferred)"); 336 return;
| 286 /* Remove rulesets by commiting empty ones. */ 287 err = 0; 288 if (prepare_commit(s->id) == -1) 289 err = errno; 290 else if (do_commit() == -1) { 291 err = errno; 292 do_rollback();
|
337 }
| 293 }
|
| 294 if (err) 295 logmsg(LOG_ERR, "#%d pf rule removal failed: %s", s->id, 296 strerror(err));
|
338
| 297
|
339 len = sizeof(tbuf);
| 298 LIST_REMOVE(s, entry); 299 free(s); 300 session_count--; 301}
|
340
| 302
|
341 if (delta >= 60) { 342 int idelta;
| 303int 304exit_daemon(void) 305{ 306 struct session *s, *next;
|
343
| 307
|
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, 349 idelta % 60); 350 if (i == -1 || i >= len) 351 goto logit; 352 len -= i; 353 } else { 354 i = snprintf(tbuf, len, 355 "data transfer complete (%dm %ds", idelta / 60, 356 idelta % 60); 357 if (i == -1 || i >= len) 358 goto logit; 359 len -= i; 360 } 361 } else { 362 i = snprintf(tbuf, len, "data transfer complete (%.1fs", 363 delta); 364 if (i == -1 || i >= len) 365 goto logit; 366 len -= i;
| 308#ifdef __FreeBSD__ 309 LIST_FOREACH_SAFE(s, &sessions, entry, next) { 310#else 311 for (s = LIST_FIRST(&sessions); s != LIST_END(&sessions); s = next) { 312 next = LIST_NEXT(s, entry); 313#endif 314 end_session(s);
|
367 } 368
| 315 } 316
|
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) 374 goto logit; 375 len -= i; 376 } 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) 382 goto logit; 383 len -= i; 384 } 385 strlcat(tbuf, ")", sizeof(tbuf)); 386 logit: 387 if (i != -1) 388 syslog(LOG_INFO, "%s", tbuf); 389}
| 317 if (daemonize) 318 closelog();
|
390
| 319
|
391void 392log_control_command (char *cmd, int client) 393{ 394 /* log an ftp control command or reply */ 395 const char *logstring; 396 int level = LOG_DEBUG;
| 320 exit(0);
|
397
| 321
|
398 if (!Verbose) 399 return; 400 401 /* don't log passwords */ 402 if (strncasecmp(cmd, "pass ", 5) == 0) 403 logstring = "PASS XXXX"; 404 else 405 logstring = cmd; 406 if (client) { 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)) 412 level = LOG_INFO; 413 } 414 syslog(level, "%s %s", client ? "client:" : " server:", 415 logstring);
| 322 /* NOTREACHED */ 323 return (-1);
|
416} 417
| 324} 325
|
418/* 419 * set ourselves up for a new data connection. Direction is toward client if 420 * "server" is 0, towards server otherwise. 421 */
| |
422int
| 326int
|
423new_dataconn(int server)
| 327getline(char *buf, size_t *valid)
|
424{
| 328{
|
425 /* 426 * Close existing data conn. 427 */
| 329 size_t i;
|
428
| 330
|
429 if (client_listen_socket != -1) { 430 close(client_listen_socket); 431 client_listen_socket = -1;
| 331 if (*valid > MAX_LINE) 332 return (-1); 333 334 /* Copy to linebuf while searching for a newline. */ 335 for (i = 0; i < *valid; i++) { 336 linebuf[i] = buf[i]; 337 if (buf[i] == '\0') 338 return (-1); 339 if (buf[i] == '\n') 340 break;
|
432 }
| 341 }
|
433 close_client_data();
| |
434
| 342
|
435 if (server_listen_socket != -1) { 436 close(server_listen_socket); 437 server_listen_socket = -1;
| 343 if (i == *valid) { 344 /* No newline found. */ 345 linebuf[0] = '\0'; 346 linelen = 0; 347 if (i < MAX_LINE) 348 return (0); 349 return (-1);
|
438 }
| 350 }
|
439 close_server_data();
| |
440
| 351
|
441 if (server) { 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);
| 352 linelen = i + 1; 353 linebuf[linelen] = '\0'; 354 *valid -= linelen; 355 356 /* Move leftovers to the start. */ 357 if (*valid != 0) 358 bcopy(buf + linelen, buf, *valid);
|
445
| 359
|
446 if (server_listen_socket == -1) { 447 syslog(LOG_INFO, "server socket bind() failed (%m)"); 448 exit(EX_OSERR); 449 } 450 if (listen(server_listen_socket, 5) != 0) { 451 syslog(LOG_INFO, "server socket listen() failed (%m)"); 452 exit(EX_OSERR); 453 } 454 } else { 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); 458 459 if (client_listen_socket == -1) { 460 syslog(LOG_NOTICE, 461 "cannot get client listen socket (%m)"); 462 exit(EX_OSERR); 463 } 464 if (listen(client_listen_socket, 5) != 0) { 465 syslog(LOG_NOTICE, 466 "cannot listen on client socket (%m)"); 467 exit(EX_OSERR); 468 } 469 } 470 return(0);
| 360 return ((int)linelen);
|
471} 472
| 361} 362
|
473static void 474connect_pasv_backchannel(void)
| 363void 364handle_connection(const int listen_fd, short event, void *ev)
|
475{
| 365{
|
476 struct sockaddr_in listen_sa; 477 socklen_t salen;
| 366 struct sockaddr_storage tmp_ss; 367 struct sockaddr *client_sa, *server_sa, *fixed_server_sa; 368 struct sockaddr *client_to_proxy_sa, *proxy_to_server_sa; 369 struct session *s; 370 socklen_t len; 371 int client_fd, fc, on;
|
478 479 /*
| 372 373 /*
|
480 * We are about to accept a connection from the client. 481 * This is a PASV data connection.
| 374 * We _must_ accept the connection, otherwise libevent will keep 375 * coming back, and we will chew up all CPU.
|
482 */
| 376 */
|
483 debuglog(2, "client listen socket ready");
| 377 client_sa = sstosa(&tmp_ss); 378 len = sizeof(struct sockaddr_storage); 379 if ((client_fd = accept(listen_fd, client_sa, &len)) < 0) { 380 logmsg(LOG_CRIT, "accept failed: %s", strerror(errno)); 381 return; 382 }
|
484
| 383
|
485 close_server_data(); 486 close_client_data();
| 384 /* Refuse connection if the maximum is reached. */ 385 if (session_count >= max_sessions) { 386 logmsg(LOG_ERR, "client limit (%d) reached, refusing " 387 "connection from %s", max_sessions, sock_ntop(client_sa)); 388 close(client_fd); 389 return; 390 }
|
487
| 391
|
488 salen = sizeof(listen_sa); 489 client_data_socket = accept(client_listen_socket, 490 (struct sockaddr *)&listen_sa, &salen); 491 492 if (client_data_socket < 0) { 493 syslog(LOG_NOTICE, "accept() failed (%m)"); 494 exit(EX_OSERR);
| 392 /* Allocate session and copy back the info from the accept(). */ 393 s = init_session(); 394 if (s == NULL) { 395 logmsg(LOG_CRIT, "init_session failed"); 396 close(client_fd); 397 return;
|
495 }
| 398 }
|
496 close(client_listen_socket); 497 client_listen_socket = -1; 498 memset(&listen_sa, 0, sizeof(listen_sa));
| 399 s->client_fd = client_fd; 400 memcpy(sstosa(&s->client_ss), client_sa, client_sa->sa_len);
|
499
| 401
|
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)"); 504 exit(EX_OSERR);
| 402 /* Cast it once, and be done with it. */ 403 client_sa = sstosa(&s->client_ss); 404 server_sa = sstosa(&s->server_ss); 405 client_to_proxy_sa = sstosa(&tmp_ss); 406 proxy_to_server_sa = sstosa(&s->proxy_ss); 407 fixed_server_sa = sstosa(&fixed_server_ss); 408 409 /* Log id/client early to ease debugging. */ 410 logmsg(LOG_DEBUG, "#%d accepted connection from %s", s->id, 411 sock_ntop(client_sa)); 412 413 /* 414 * Find out the real server and port that the client wanted. 415 */ 416 len = sizeof(struct sockaddr_storage); 417 if ((getsockname(s->client_fd, client_to_proxy_sa, &len)) < 0) { 418 logmsg(LOG_CRIT, "#%d getsockname failed: %s", s->id, 419 strerror(errno)); 420 goto fail;
|
505 }
| 421 }
|
506 if (connect(server_data_socket, (struct sockaddr *) &server_listen_sa, 507 sizeof(server_listen_sa)) != 0) { 508 syslog(LOG_NOTICE, "connect() failed (%m)"); 509 exit(EX_NOHOST);
| 422 if (server_lookup(client_sa, client_to_proxy_sa, server_sa) != 0) { 423 logmsg(LOG_CRIT, "#%d server lookup failed (no rdr?)", s->id); 424 goto fail;
|
510 }
| 425 }
|
511 client_data_bytes = 0; 512 server_data_bytes = 0; 513 xfer_start_time = wallclock_time(); 514}
| 426 if (fixed_server) { 427 memcpy(sstosa(&s->orig_server_ss), server_sa, 428 server_sa->sa_len); 429 memcpy(server_sa, fixed_server_sa, fixed_server_sa->sa_len); 430 }
|
515
| 431
|
516static void 517connect_port_backchannel(void) 518{ 519 struct sockaddr_in listen_sa; 520 socklen_t salen;
| 432 /* XXX: check we are not connecting to ourself. */
|
521 522 /*
| 433 434 /*
|
523 * We are about to accept a connection from the server. 524 * This is a PORT or EPRT data connection.
| 435 * Setup socket and connect to server.
|
525 */
| 436 */
|
526 debuglog(2, "server listen socket ready");
| 437 if ((s->server_fd = socket(server_sa->sa_family, SOCK_STREAM, 438 IPPROTO_TCP)) < 0) { 439 logmsg(LOG_CRIT, "#%d server socket failed: %s", s->id, 440 strerror(errno)); 441 goto fail; 442 } 443 if (fixed_proxy && bind(s->server_fd, sstosa(&fixed_proxy_ss), 444 fixed_proxy_ss.ss_len) != 0) { 445 logmsg(LOG_CRIT, "#%d cannot bind fixed proxy address: %s", 446 s->id, strerror(errno)); 447 goto fail; 448 }
|
527
| 449
|
528 close_server_data(); 529 close_client_data();
| 450 /* Use non-blocking connect(), see CONNECT_TIMEOUT below. */ 451 if ((fc = fcntl(s->server_fd, F_GETFL)) == -1 || 452 fcntl(s->server_fd, F_SETFL, fc | O_NONBLOCK) == -1) { 453 logmsg(LOG_CRIT, "#%d cannot mark socket non-blocking: %s", 454 s->id, strerror(errno)); 455 goto fail; 456 } 457 if (connect(s->server_fd, server_sa, server_sa->sa_len) < 0 && 458 errno != EINPROGRESS) { 459 logmsg(LOG_CRIT, "#%d proxy cannot connect to server %s: %s", 460 s->id, sock_ntop(server_sa), strerror(errno)); 461 goto fail; 462 }
|
530
| 463
|
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)"); 536 exit(EX_OSERR);
| 464 len = sizeof(struct sockaddr_storage); 465 if ((getsockname(s->server_fd, proxy_to_server_sa, &len)) < 0) { 466 logmsg(LOG_CRIT, "#%d getsockname failed: %s", s->id, 467 strerror(errno)); 468 goto fail;
|
537 }
| 469 }
|
538 close(server_listen_socket); 539 server_listen_socket = -1;
| |
540
| 470
|
541 if (getuid() != 0) { 542 /* 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 546 * not RFC compliant. 547 */ 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)"); 553 exit(EX_OSERR); 554 }
| 471 logmsg(LOG_INFO, "#%d FTP session %d/%d started: client %s to server " 472 "%s via proxy %s ", s->id, session_count, max_sessions, 473 sock_ntop(client_sa), sock_ntop(server_sa), 474 sock_ntop(proxy_to_server_sa));
|
555
| 475
|
556 } else {
| 476 /* Keepalive is nice, but don't care if it fails. */ 477 on = 1; 478 setsockopt(s->client_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, 479 sizeof on); 480 setsockopt(s->server_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, 481 sizeof on);
|
557
| 482
|
558 /* 559 * We're root, get our backchannel socket bound to port 560 * 20 here, so we're fully RFC compliant. 561 */ 562 client_data_socket = socket(AF_INET, SOCK_STREAM, 0); 563 564 salen = 1; 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); 568 569 if (setsockopt(client_data_socket, SOL_SOCKET, SO_REUSEADDR, 570 &salen, sizeof(salen)) == -1) { 571 syslog(LOG_NOTICE, "setsockopt() failed (%m)"); 572 exit(EX_OSERR); 573 } 574 575 if (bind(client_data_socket, (struct sockaddr *)&listen_sa, 576 sizeof(listen_sa)) == - 1) { 577 syslog(LOG_NOTICE, "data channel bind() failed (%m)"); 578 exit(EX_OSERR); 579 }
| 483 /* 484 * Setup buffered events. 485 */ 486 s->client_bufev = bufferevent_new(s->client_fd, &client_read, NULL, 487 &client_error, s); 488 if (s->client_bufev == NULL) { 489 logmsg(LOG_CRIT, "#%d bufferevent_new client failed", s->id); 490 goto fail;
|
580 }
| 491 }
|
| 492 bufferevent_settimeout(s->client_bufev, timeout, 0); 493 bufferevent_enable(s->client_bufev, EV_READ | EV_TIMEOUT);
|
581
| 494
|
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)"); 585 exit(EX_NOHOST);
| 495 s->server_bufev = bufferevent_new(s->server_fd, &server_read, NULL, 496 &server_error, s); 497 if (s->server_bufev == NULL) { 498 logmsg(LOG_CRIT, "#%d bufferevent_new server failed", s->id); 499 goto fail;
|
586 }
| 500 }
|
| 501 bufferevent_settimeout(s->server_bufev, CONNECT_TIMEOUT, 0); 502 bufferevent_enable(s->server_bufev, EV_READ | EV_TIMEOUT);
|
587
| 503
|
588 client_data_bytes = 0; 589 server_data_bytes = 0; 590 xfer_start_time = wallclock_time();
| 504 return; 505 506 fail: 507 end_session(s);
|
591} 592 593void
| 508} 509 510void
|
594do_client_cmd(struct csiob *client, struct csiob *server)
| 511handle_signal(int sig, short event, void *arg)
|
595{
| 512{
|
596 int i, j, rv; 597 char tbuf[100]; 598 char *sendbuf = NULL; 599 600 log_control_command((char *)client->line_buffer, 1); 601 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. 606 */ 607 if (strlen((char *)client->line_buffer) > 512) { 608 syslog(LOG_NOTICE, "excessively long control command"); 609 exit(EX_DATAERR); 610 } 611
| |
612 /*
| 513 /*
|
613 * Check the client user provided if needed
| 514 * Signal handler rules don't apply, libevent decouples for us.
|
614 */
| 515 */
|
615 if (AnonFtpOnly && strncasecmp((char *)client->line_buffer, "user ", 616 strlen("user ")) == 0) { 617 char *cp;
| |
618
| 516
|
619 cp = (char *) client->line_buffer + strlen("user "); 620 if ((strcasecmp(cp, "ftp\r\n") != 0) && 621 (strcasecmp(cp, "anonymous\r\n") != 0)) { 622 /* 623 * this isn't anonymous - give the client an 624 * error before they send a password 625 */ 626 snprintf(tbuf, sizeof(tbuf), 627 "500 Only anonymous FTP is allowed\r\n"); 628 j = 0; 629 i = strlen(tbuf); 630 do { 631 rv = send(client->fd, tbuf + j, i - j, 0); 632 if (rv == -1 && errno != EAGAIN && 633 errno != EINTR) 634 break; 635 else if (rv != -1) 636 j += rv; 637 } while (j >= 0 && j < i); 638 sendbuf = NULL; 639 } else 640 sendbuf = (char *)client->line_buffer; 641 } else if ((strncasecmp((char *)client->line_buffer, "eprt ", 642 strlen("eprt ")) == 0)) {
| 517 logmsg(LOG_ERR, "%s exiting on signal %d", __progname, sig);
|
643
| 518
|
644 /* Watch out for EPRT commands */ 645 char *line = NULL, *q, *p, *result[3], delim; 646 struct addrinfo hints, *res = NULL; 647 unsigned long proto;
| 519 exit_daemon(); 520} 521
|
648
| 522
|
649 j = 0; 650 line = strdup((char *)client->line_buffer+strlen("eprt ")); 651 if (line == NULL) { 652 syslog(LOG_ERR, "insufficient memory"); 653 exit(EX_UNAVAILABLE); 654 } 655 p = line; 656 delim = p[0]; 657 p++;
| 523struct session * 524init_session(void) 525{ 526 struct session *s;
|
658
| 527
|
659 memset(result,0, sizeof(result)); 660 for (i = 0; i < 3; i++) { 661 q = strchr(p, delim); 662 if (!q || *q != delim) 663 goto parsefail; 664 *q++ = '\0'; 665 result[i] = p; 666 p = q; 667 }
| 528 s = calloc(1, sizeof(struct session)); 529 if (s == NULL) 530 return (NULL);
|
668
| 531
|
669 proto = strtoul(result[0], &p, 10); 670 if (!*result[0] || *p) 671 goto protounsupp;
| 532 s->id = id_count++; 533 s->client_fd = -1; 534 s->server_fd = -1; 535 s->cbuf[0] = '\0'; 536 s->cbuf_valid = 0; 537 s->sbuf[0] = '\0'; 538 s->sbuf_valid = 0; 539 s->client_bufev = NULL; 540 s->server_bufev = NULL; 541 s->cmd = CMD_NONE; 542 s->port = 0;
|
672
| 543
|
673 memset(&hints, 0, sizeof(hints)); 674 if (proto != 1) /* 1 == AF_INET - all we support for now */ 675 goto protounsupp; 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)) 680 goto parsefail; 681 if (res->ai_next) 682 goto parsefail; 683 if (sizeof(client_listen_sa) < res->ai_addrlen) 684 goto parsefail; 685 memcpy(&client_listen_sa, res->ai_addr, res->ai_addrlen);
| 544 LIST_INSERT_HEAD(&sessions, s, entry); 545 session_count++;
|
686
| 546
|
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)); 690 691 /* 692 * Configure our own listen socket and tell the server about it 693 */ 694 new_dataconn(1); 695 connection_mode = EPRT_MODE; 696 697 debuglog(1, "we want server to use %s:%u", 698 inet_ntoa(server->sa.sin_addr), 699 ntohs(server_listen_sa.sin_port)); 700 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); 705 sendbuf = tbuf; 706 goto out; 707parsefail: 708 snprintf(tbuf, sizeof(tbuf), 709 "500 Invalid argument; rejected\r\n"); 710 sendbuf = NULL; 711 goto out; 712protounsupp: 713 /* we only support AF_INET for now */ 714 if (proto == 2) 715 snprintf(tbuf, sizeof(tbuf), 716 "522 Protocol not supported, use (1)\r\n"); 717 else 718 snprintf(tbuf, sizeof(tbuf), 719 "501 Protocol not supported\r\n"); 720 sendbuf = NULL; 721out: 722 if (line) 723 free(line); 724 if (res) 725 freeaddrinfo(res); 726 if (sendbuf == NULL) { 727 debuglog(1, "to client (modified): %s", tbuf); 728 i = strlen(tbuf); 729 do { 730 rv = send(client->fd, tbuf + j, i - j, 0); 731 if (rv == -1 && errno != EAGAIN && 732 errno != EINTR) 733 break; 734 else if (rv != -1) 735 j += rv; 736 } while (j >= 0 && j < i); 737 } 738 } else if (!NatMode && (strncasecmp((char *)client->line_buffer, 739 "epsv", strlen("epsv")) == 0)) { 740 741 /* 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. 750 * 751 * in the meantime we just tell the client we don't do it, 752 * and most clients should fall back to using PASV. 753 */ 754 755 snprintf(tbuf, sizeof(tbuf), 756 "500 EPSV command not understood\r\n"); 757 debuglog(1, "to client (modified): %s", tbuf); 758 j = 0; 759 i = strlen(tbuf); 760 do { 761 rv = send(client->fd, tbuf + j, i - j, 0); 762 if (rv == -1 && errno != EAGAIN && errno != EINTR) 763 break; 764 else if (rv != -1) 765 j += rv; 766 } while (j >= 0 && j < i); 767 sendbuf = NULL; 768 } else if (strncasecmp((char *)client->line_buffer, "port ", 769 strlen("port ")) == 0) { 770 unsigned int values[6]; 771 char *tailptr; 772 773 debuglog(1, "Got a PORT command"); 774 775 tailptr = (char *)&client->line_buffer[strlen("port ")]; 776 values[0] = 0; 777 778 i = sscanf(tailptr, "%u,%u,%u,%u,%u,%u", &values[0], 779 &values[1], &values[2], &values[3], &values[4], 780 &values[5]); 781 if (i != 6) { 782 syslog(LOG_INFO, "malformed PORT command (%s)", 783 client->line_buffer); 784 exit(EX_DATAERR); 785 } 786 787 for (i = 0; i<6; i++) { 788 if (values[i] > 255) { 789 syslog(LOG_INFO, 790 "malformed PORT command (%s)", 791 client->line_buffer); 792 exit(EX_DATAERR); 793 } 794 } 795 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) | 799 (values[3] << 0)); 800 801 client_listen_sa.sin_port = htons((values[4] << 8) | 802 values[5]); 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]); 806 807 /* 808 * Configure our own listen socket and tell the server about it 809 */ 810 new_dataconn(1); 811 connection_mode = PORT_MODE; 812 813 debuglog(1, "we want server to use %s:%u", 814 inet_ntoa(server->sa.sin_addr), 815 ntohs(server_listen_sa.sin_port)); 816 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]); 824 825 debuglog(1, "to server (modified): %s", tbuf); 826 827 sendbuf = tbuf; 828 } else 829 sendbuf = (char *)client->line_buffer; 830 831 /* 832 *send our (possibly modified) control command in sendbuf 833 * on it's way to the server 834 */ 835 if (sendbuf != NULL) { 836 j = 0; 837 i = strlen(sendbuf); 838 do { 839 rv = send(server->fd, sendbuf + j, i - j, 0); 840 if (rv == -1 && errno != EAGAIN && errno != EINTR) 841 break; 842 else if (rv != -1) 843 j += rv; 844 } while (j >= 0 && j < i); 845 }
| 547 return (s);
|
846} 847 848void
| 548} 549 550void
|
849do_server_reply(struct csiob *server, struct csiob *client)
| 551logmsg(int pri, const char *message, ...)
|
850{
| 552{
|
851 int code, i, j, rv; 852 struct in_addr *iap; 853 static int continuing = 0; 854 char tbuf[100], *sendbuf, *p;
| 553 va_list ap;
|
855
| 554
|
856 log_control_command((char *)server->line_buffer, 0);
| 555 if (pri > loglevel) 556 return;
|
857
| 557
|
858 if (strlen((char *)server->line_buffer) > 512) { 859 /* 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. 863 */ 864 syslog(LOG_NOTICE, "long FTP control reply"); 865 exit(EX_DATAERR); 866 }
| 558 va_start(ap, message);
|
867
| 559
|
868 /* 869 * Watch out for "227 Entering Passive Mode ..." replies 870 */ 871 code = strtol((char *)server->line_buffer, &p, 10); 872 if (isspace(server->line_buffer[0])) 873 code = 0; 874 if (!*(server->line_buffer) || (*p != ' ' && *p != '-')) { 875 if (continuing) 876 goto sendit; 877 syslog(LOG_INFO, "malformed control reply"); 878 exit(EX_DATAERR); 879 } 880 if (code <= 0 || code > 999) { 881 if (continuing) 882 goto sendit; 883 syslog(LOG_INFO, "invalid server reply code %d", code); 884 exit(EX_DATAERR); 885 } 886 if (*p == '-') 887 continuing = 1; 888 else 889 continuing = 0; 890 if (code == 227 && !NatMode) { 891 unsigned int values[6]; 892 char *tailptr;
| 560 if (daemonize) 561 /* syslog does its own vissing. */ 562 vsyslog(pri, message, ap); 563 else { 564 char buf[MAX_LOGLINE]; 565 char visbuf[2 * MAX_LOGLINE];
|
893
| 566
|
894 debuglog(1, "Got a PASV reply"); 895 debuglog(1, "{%s}", (char *)server->line_buffer); 896 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"); 902 exit(EX_DATAERR); 903 } 904 } 905 tailptr++; /* skip past space or ( */ 906 907 values[0] = 0; 908 909 i = sscanf(tailptr, "%u,%u,%u,%u,%u,%u", &values[0], 910 &values[1], &values[2], &values[3], &values[4], 911 &values[5]); 912 if (i != 6) { 913 syslog(LOG_INFO, "malformed PASV reply (%s)", 914 client->line_buffer); 915 exit(EX_DATAERR); 916 } 917 for (i = 0; i<6; i++) 918 if (values[i] > 255) { 919 syslog(LOG_INFO, "malformed PASV reply(%s)", 920 client->line_buffer); 921 exit(EX_DATAERR); 922 } 923 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) | 928 values[5]); 929 930 debuglog(1, "server wants us to use %s:%u", 931 inet_ntoa(server_listen_sa.sin_addr), (values[4] << 8) | 932 values[5]); 933 934 new_dataconn(0); 935 connection_mode = PASV_MODE; 936 if (ReverseMode) 937 iap = &(proxy_sa.sin_addr); 938 else 939 iap = &(server->sa.sin_addr); 940 941 debuglog(1, "we want client to use %s:%u", inet_ntoa(*iap), 942 htons(client_listen_sa.sin_port)); 943 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); 951 sendbuf = tbuf; 952 } else { 953 sendit: 954 sendbuf = (char *)server->line_buffer;
| 567 /* We don't care about truncation. */ 568 vsnprintf(buf, sizeof buf, message, ap); 569#ifdef __FreeBSD__ 570 /* XXX: strnvis might be nice to have */ 571 strvisx(visbuf, buf, 572 MIN((sizeof(visbuf) / 4) - 1, strlen(buf)), 573 VIS_CSTYLE | VIS_NL); 574#else 575 strnvis(visbuf, buf, sizeof visbuf, VIS_CSTYLE | VIS_NL); 576#endif 577 fprintf(stderr, "%s\n", visbuf);
|
955 } 956
| 578 } 579
|
957 /* 958 * send our (possibly modified) control command in sendbuf 959 * on it's way to the client 960 */ 961 j = 0; 962 i = strlen(sendbuf); 963 do { 964 rv = send(client->fd, sendbuf + j, i - j, 0); 965 if (rv == -1 && errno != EAGAIN && errno != EINTR) 966 break; 967 else if (rv != -1) 968 j += rv; 969 } while (j >= 0 && j < i); 970
| 580 va_end(ap);
|
971} 972 973int 974main(int argc, char *argv[]) 975{
| 581} 582 583int 584main(int argc, char *argv[]) 585{
|
976 struct csiob client_iob, server_iob; 977 struct sigaction new_sa, old_sa; 978 int sval, ch, flags, i; 979 socklen_t salen; 980 int one = 1; 981 long timeout_seconds = 0; 982 struct timeval tv; 983#ifdef LIBWRAP 984 int use_tcpwrapper = 0; 985#endif /* LIBWRAP */
| 586 struct rlimit rlp; 587 struct addrinfo hints, *res; 588 struct event ev, ev_sighup, ev_sigint, ev_sigterm; 589 int ch, error, listenfd, on; 590 const char *errstr;
|
986
| 591
|
987 while ((ch = getopt(argc, argv, "a:D:g:m:M:R:S:t:u:AnVwr")) != -1) { 988 char *p;
| 592 /* Defaults. */ 593 anonymous_only = 0; 594 daemonize = 1; 595 fixed_proxy = NULL; 596 fixed_server = NULL; 597 fixed_server_port = "21"; 598 ipv6_mode = 0; 599 listen_ip = NULL; 600 listen_port = "8021"; 601 loglevel = LOG_NOTICE; 602 max_sessions = 100; 603 qname = NULL; 604 rfc_mode = 0; 605 timeout = 24 * 3600; 606 verbose = 0; 607 608 /* Other initialization. */ 609 id_count = 1; 610 session_count = 0; 611 612 while ((ch = getopt(argc, argv, "6Aa:b:D:dm:P:p:q:R:rt:v")) != -1) {
|
989 switch (ch) {
| 613 switch (ch) {
|
990 case 'a': 991 if (!*optarg) 992 usage(); 993 if ((Bind_Addr = inet_addr(optarg)) == INADDR_NONE) { 994 syslog(LOG_NOTICE, 995 "%s: invalid address", optarg); 996 usage(); 997 }
| 614 case '6': 615 ipv6_mode = 1;
|
998 break; 999 case 'A':
| 616 break; 617 case 'A':
|
1000 AnonFtpOnly = 1; /* restrict to anon usernames only */
| 618 anonymous_only = 1;
|
1001 break;
| 619 break;
|
| 620 case 'a': 621 fixed_proxy = optarg; 622 break; 623 case 'b': 624 listen_ip = optarg; 625 break;
|
1002 case 'D':
| 626 case 'D':
|
1003 Debug_Level = strtol(optarg, &p, 10); 1004 if (!*optarg || *p) 1005 usage();
| 627 loglevel = strtonum(optarg, LOG_EMERG, LOG_DEBUG, 628 &errstr); 629 if (errstr) 630 errx(1, "loglevel %s", errstr);
|
1006 break;
| 631 break;
|
1007 case 'g': 1008 Group = optarg;
| 632 case 'd': 633 daemonize = 0;
|
1009 break; 1010 case 'm':
| 634 break; 635 case 'm':
|
1011 min_port = strtol(optarg, &p, 10); 1012 if (!*optarg || *p) 1013 usage(); 1014 if (min_port < 0 || min_port > USHRT_MAX) 1015 usage();
| 636 max_sessions = strtonum(optarg, 1, 500, &errstr); 637 if (errstr) 638 errx(1, "max sessions %s", errstr);
|
1016 break;
| 639 break;
|
1017 case 'M': 1018 max_port = strtol(optarg, &p, 10); 1019 if (!*optarg || *p) 1020 usage(); 1021 if (max_port < 0 || max_port > USHRT_MAX) 1022 usage();
| 640 case 'P': 641 fixed_server_port = optarg;
|
1023 break;
| 642 break;
|
1024 case 'n': 1025 NatMode = 1; /* pass all passives, we're using NAT */
| 643 case 'p': 644 listen_port = optarg;
|
1026 break;
| 645 break;
|
1027 case 'r': 1028 Use_Rdns = 1; /* look up hostnames */
| 646 case 'q': 647 if (strlen(optarg) >= PF_QNAME_SIZE) 648 errx(1, "queuename too long"); 649 qname = optarg;
|
1029 break;
| 650 break;
|
1030 case 'R': { 1031 char *s, *t; 1032 1033 if (!*optarg) 1034 usage(); 1035 if ((s = strdup(optarg)) == NULL) { 1036 syslog (LOG_NOTICE, 1037 "Insufficient memory (malloc failed)"); 1038 exit(EX_UNAVAILABLE); 1039 } 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; 1043 t = strchr(s, ':'); 1044 if (t == NULL) 1045 real_server_sa.sin_port = htons(21); 1046 else { 1047 long port = strtol(t + 1, &p, 10); 1048 1049 if (*p || port <= 0 || port > 65535) 1050 usage(); 1051 real_server_sa.sin_port = htons(port); 1052 *t = 0; 1053 } 1054 real_server_sa.sin_addr.s_addr = inet_addr(s); 1055 if (real_server_sa.sin_addr.s_addr == INADDR_NONE) 1056 usage(); 1057 free(s); 1058 ReverseMode = 1;
| 651 case 'R': 652 fixed_server = optarg;
|
1059 break;
| 653 break;
|
1060 } 1061 case 'S': 1062 if (!inet_aton(optarg, &src_addr)) 1063 usage();
| 654 case 'r': 655 rfc_mode = 1;
|
1064 break; 1065 case 't':
| 656 break; 657 case 't':
|
1066 timeout_seconds = strtol(optarg, &p, 10); 1067 if (!*optarg || *p)
| 658 timeout = strtonum(optarg, 0, 86400, &errstr); 659 if (errstr) 660 errx(1, "timeout %s", errstr); 661 break; 662 case 'v': 663 verbose++; 664 if (verbose > 2)
|
1068 usage(); 1069 break;
| 665 usage(); 666 break;
|
1070 case 'u': 1071 User = optarg; 1072 break; 1073 case 'V': 1074 Verbose = 1; 1075 break; 1076#ifdef LIBWRAP 1077 case 'w': 1078 use_tcpwrapper = 1; /* do the libwrap thing */ 1079 break; 1080#endif /* LIBWRAP */
| |
1081 default: 1082 usage();
| 667 default: 668 usage();
|
1083 /* NOTREACHED */
| |
1084 } 1085 }
| 669 } 670 }
|
1086 argc -= optind; 1087 argv += optind;
| |
1088
| 671
|
1089 if (max_port < min_port) 1090 usage();
| 672 if (listen_ip == NULL) 673 listen_ip = ipv6_mode ? "::1" : "127.0.0.1";
|
1091
| 674
|
1092 openlog(__progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
| 675 /* Check for root to save the user from cryptic failure messages. */ 676 if (getuid() != 0) 677 errx(1, "needs to start as root");
|
1093
| 678
|
1094 setlinebuf(stdout); 1095 setlinebuf(stderr);
| 679 /* Raise max. open files limit to satisfy max. sessions. */ 680 rlp.rlim_cur = rlp.rlim_max = (2 * max_sessions) + 10; 681 if (setrlimit(RLIMIT_NOFILE, &rlp) == -1) 682 err(1, "setrlimit");
|
1096
| 683
|
1097 memset(&client_iob, 0, sizeof(client_iob)); 1098 memset(&server_iob, 0, sizeof(server_iob));
| 684 if (fixed_proxy) { 685 memset(&hints, 0, sizeof hints); 686 hints.ai_flags = AI_NUMERICHOST; 687 hints.ai_family = ipv6_mode ? AF_INET6 : AF_INET; 688 hints.ai_socktype = SOCK_STREAM; 689 error = getaddrinfo(fixed_proxy, NULL, &hints, &res); 690 if (error) 691 errx(1, "getaddrinfo fixed proxy address failed: %s", 692 gai_strerror(error)); 693 memcpy(&fixed_proxy_ss, res->ai_addr, res->ai_addrlen); 694 logmsg(LOG_INFO, "using %s to connect to servers", 695 sock_ntop(sstosa(&fixed_proxy_ss))); 696 freeaddrinfo(res); 697 }
|
1099
| 698
|
1100 if (get_proxy_env(0, &real_server_sa, &client_iob.sa, 1101 &proxy_sa) == -1) 1102 exit(EX_PROTOCOL);
| 699 if (fixed_server) { 700 memset(&hints, 0, sizeof hints); 701 hints.ai_family = ipv6_mode ? AF_INET6 : AF_INET; 702 hints.ai_socktype = SOCK_STREAM; 703 error = getaddrinfo(fixed_server, fixed_server_port, &hints, 704 &res); 705 if (error) 706 errx(1, "getaddrinfo fixed server address failed: %s", 707 gai_strerror(error)); 708 memcpy(&fixed_server_ss, res->ai_addr, res->ai_addrlen); 709 logmsg(LOG_INFO, "using fixed server %s", 710 sock_ntop(sstosa(&fixed_server_ss))); 711 freeaddrinfo(res); 712 }
|
1103
| 713
|
1104 /* 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. 1110 */ 1111 drop_privs();
| 714 /* Setup listener. */ 715 memset(&hints, 0, sizeof hints); 716 hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; 717 hints.ai_family = ipv6_mode ? AF_INET6 : AF_INET; 718 hints.ai_socktype = SOCK_STREAM; 719 error = getaddrinfo(listen_ip, listen_port, &hints, &res); 720 if (error) 721 errx(1, "getaddrinfo listen address failed: %s", 722 gai_strerror(error)); 723 if ((listenfd = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP)) == -1) 724 errx(1, "socket failed"); 725 on = 1; 726 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, 727 sizeof on) != 0) 728 err(1, "setsockopt failed"); 729 if (bind(listenfd, (struct sockaddr *)res->ai_addr, 730 (socklen_t)res->ai_addrlen) != 0) 731 err(1, "bind failed"); 732 if (listen(listenfd, TCP_BACKLOG) != 0) 733 err(1, "listen failed"); 734 freeaddrinfo(res);
|
1112
| 735
|
1113 /* 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 1118 * for ftp. 1119 */ 1120 if (Use_Rdns) 1121 flags = 0; 1122 else 1123 flags = NI_NUMERICHOST | NI_NUMERICSERV;
| 736 /* Initialize pf. */ 737 init_filter(qname, verbose);
|
1124
| 738
|
1125 i = getnameinfo((struct sockaddr *)&client_iob.sa, 1126 sizeof(client_iob.sa), ClientName, sizeof(ClientName), NULL, 0, 1127 flags);
| 739 if (daemonize) { 740 if (daemon(0, 0) == -1) 741 err(1, "cannot daemonize"); 742 openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON); 743 }
|
1128
| 744
|
1129 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) { 1130 debuglog(2, "name resolution failure (client)"); 1131 exit(EX_OSERR);
| 745 /* Use logmsg for output from here on. */ 746 747 if (!drop_privs()) { 748 logmsg(LOG_ERR, "cannot drop privileges: %s", strerror(errno)); 749 exit(1);
|
1132 }
| 750 }
|
| 751 752 event_init();
|
1133
| 753
|
1134 i = getnameinfo((struct sockaddr *)&real_server_sa, 1135 sizeof(real_server_sa), RealServerName, sizeof(RealServerName), 1136 NULL, 0, flags);
| 754 /* Setup signal handler. */ 755 signal(SIGPIPE, SIG_IGN); 756 signal_set(&ev_sighup, SIGHUP, handle_signal, NULL); 757 signal_set(&ev_sigint, SIGINT, handle_signal, NULL); 758 signal_set(&ev_sigterm, SIGTERM, handle_signal, NULL); 759 signal_add(&ev_sighup, NULL); 760 signal_add(&ev_sigint, NULL); 761 signal_add(&ev_sigterm, NULL);
|
1137
| 762
|
1138 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) { 1139 debuglog(2, "name resolution failure (server)"); 1140 exit(EX_OSERR);
| 763 event_set(&ev, listenfd, EV_READ | EV_PERSIST, handle_connection, &ev); 764 event_add(&ev, NULL); 765 766 logmsg(LOG_NOTICE, "listening on %s port %s", listen_ip, listen_port); 767 768 /* Vroom, vroom. */ 769 event_dispatch(); 770 771 logmsg(LOG_ERR, "event_dispatch error: %s", strerror(errno)); 772 exit_daemon(); 773 774 /* NOTREACHED */ 775 return (1); 776} 777 778u_int16_t 779parse_port(int mode) 780{ 781 unsigned int port, v[6]; 782 int n; 783 char *p; 784 785 /* Find the last space or left-parenthesis. */ 786 for (p = linebuf + linelen; p > linebuf; p--) 787 if (*p == ' ' || *p == '(') 788 break; 789 if (p == linebuf) 790 return (0); 791 792 switch (mode) { 793 case CMD_PORT: 794 n = sscanf(p, " %u,%u,%u,%u,%u,%u", &v[0], &v[1], &v[2], 795 &v[3], &v[4], &v[5]); 796 if (n == 6 && v[0] < 256 && v[1] < 256 && v[2] < 256 && 797 v[3] < 256 && v[4] < 256 && v[5] < 256) 798 return ((v[4] << 8) | v[5]); 799 break; 800 case CMD_PASV: 801 n = sscanf(p, "(%u,%u,%u,%u,%u,%u)", &v[0], &v[1], &v[2], 802 &v[3], &v[4], &v[5]); 803 if (n == 6 && v[0] < 256 && v[1] < 256 && v[2] < 256 && 804 v[3] < 256 && v[4] < 256 && v[5] < 256) 805 return ((v[4] << 8) | v[5]); 806 break; 807 case CMD_EPSV: 808 n = sscanf(p, "(|||%u|)", &port); 809 if (n == 1 && port < 65536) 810 return (port); 811 break; 812 case CMD_EPRT: 813 n = sscanf(p, " |1|%u.%u.%u.%u|%u|", &v[0], &v[1], &v[2], 814 &v[3], &port); 815 if (n == 5 && v[0] < 256 && v[1] < 256 && v[2] < 256 && 816 v[3] < 256 && port < 65536) 817 return (port); 818 n = sscanf(p, " |2|%*[a-fA-F0-9:]|%u|", &port); 819 if (n == 1 && port < 65536) 820 return (port); 821 break; 822 default: 823 return (0);
|
1141 } 1142
| 824 } 825
|
1143#ifdef LIBWRAP 1144 if (use_tcpwrapper && !check_host(&client_iob.sa, &real_server_sa)) 1145 exit(EX_NOPERM); 1146#endif
| 826 return (0); 827}
|
1147
| 828
|
1148 client_iob.fd = 0;
| 829u_int16_t 830pick_proxy_port(void) 831{ 832 /* Random should be good enough for avoiding port collisions. */ 833 return (IPPORT_HIFIRSTAUTO + (arc4random() % 834 (IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO))); 835}
|
1149
| 836
|
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));
| 837void 838proxy_reply(int cmd, struct sockaddr *sa, u_int16_t port) 839{ 840 int i, r;
|
1153
| 841
|
1154 server_iob.fd = get_backchannel_socket(SOCK_STREAM, min_port, max_port, 1155 -1, 1, &server_iob.sa);
| 842 switch (cmd) { 843 case CMD_PORT: 844 r = snprintf(linebuf, sizeof linebuf, 845 "PORT %s,%u,%u\r\n", sock_ntop(sa), port / 256, 846 port % 256); 847 break; 848 case CMD_PASV: 849 r = snprintf(linebuf, sizeof linebuf, 850 "227 Entering Passive Mode (%s,%u,%u)\r\n", sock_ntop(sa), 851 port / 256, port % 256); 852 break; 853 case CMD_EPRT: 854 if (sa->sa_family == AF_INET) 855 r = snprintf(linebuf, sizeof linebuf, 856 "EPRT |1|%s|%u|\r\n", sock_ntop(sa), port); 857 else if (sa->sa_family == AF_INET6) 858 r = snprintf(linebuf, sizeof linebuf, 859 "EPRT |2|%s|%u|\r\n", sock_ntop(sa), port); 860 break; 861 case CMD_EPSV: 862 r = snprintf(linebuf, sizeof linebuf, 863 "229 Entering Extended Passive Mode (|||%u|)\r\n", port); 864 break; 865 }
|
1156
| 866
|
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)); 1161 exit(EX_NOHOST);
| 867 if (r < 0 || r >= sizeof linebuf) { 868 logmsg(LOG_ERR, "proxy_reply failed: %d", r); 869 linebuf[0] = '\0'; 870 linelen = 0; 871 return;
|
1162 }
| 872 }
|
| 873 linelen = (size_t)r;
|
1163
| 874
|
| 875 if (cmd == CMD_PORT || cmd == CMD_PASV) { 876 /* Replace dots in IP address with commas. */ 877 for (i = 0; i < linelen; i++) 878 if (linebuf[i] == '.') 879 linebuf[i] = ','; 880 } 881} 882 883void 884server_error(struct bufferevent *bufev, short what, void *arg) 885{ 886 struct session *s = arg; 887 888 if (what & EVBUFFER_EOF) 889 logmsg(LOG_INFO, "#%d server close", s->id); 890 else if (what == (EVBUFFER_ERROR | EVBUFFER_READ)) 891 logmsg(LOG_ERR, "#%d server refused connection", s->id); 892 else if (what & EVBUFFER_WRITE) 893 logmsg(LOG_ERR, "#%d server write error: %d", s->id, what); 894 else if (what & EVBUFFER_TIMEOUT) 895 logmsg(LOG_NOTICE, "#%d server timeout", s->id); 896 else 897 logmsg(LOG_ERR, "#%d abnormal server error: %d", s->id, what); 898 899 end_session(s); 900} 901 902int 903server_parse(struct session *s) 904{ 905 struct sockaddr *client_sa, *orig_sa, *proxy_sa, *server_sa; 906 int prepared = 0; 907 908 if (s->cmd == CMD_NONE || linelen < 4 || linebuf[0] != '2') 909 goto out; 910
|
1164 /*
| 911 /*
|
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.
| 912 * The pf rules below do quite some NAT rewriting, to keep up 913 * appearances. Points to keep in mind: 914 * 1) The client must think it's talking to the real server, 915 * for both control and data connections. Transparently. 916 * 2) The server must think that the proxy is the client. 917 * 3) Source and destination ports are rewritten to minimize 918 * port collisions, to aid security (some systems pick weak 919 * ports) or to satisfy RFC requirements (source port 20).
|
1168 */
| 920 */
|
1169 salen = sizeof(server_iob.sa); 1170 getsockname(server_iob.fd, (struct sockaddr *)&server_iob.sa, &salen);
| 921 922 /* Cast this once, to make code below it more readable. */ 923 client_sa = sstosa(&s->client_ss); 924 server_sa = sstosa(&s->server_ss); 925 proxy_sa = sstosa(&s->proxy_ss); 926 if (fixed_server) 927 /* Fixed server: data connections must appear to come 928 from / go to the original server, not the fixed one. */ 929 orig_sa = sstosa(&s->orig_server_ss); 930 else 931 /* Server not fixed: orig_server == server. */ 932 orig_sa = sstosa(&s->server_ss);
|
1171
| 933
|
1172 i = getnameinfo((struct sockaddr *)&server_iob.sa, 1173 sizeof(server_iob.sa), OurName, sizeof(OurName), NULL, 0, flags);
| 934 /* Passive modes. */ 935 if ((s->cmd == CMD_PASV && strncmp("227 ", linebuf, 4) == 0) || 936 (s->cmd == CMD_EPSV && strncmp("229 ", linebuf, 4) == 0)) { 937 s->port = parse_port(s->cmd); 938 if (s->port < MIN_PORT) { 939 logmsg(LOG_CRIT, "#%d bad port in '%s'", s->id, 940 linebuf); 941 return (0); 942 } 943 s->proxy_port = pick_proxy_port(); 944 logmsg(LOG_INFO, "#%d passive: client to server port %d" 945 " via port %d", s->id, s->port, s->proxy_port);
|
1174
| 946
|
1175 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) { 1176 debuglog(2, "name resolution failure (local)"); 1177 exit(EX_OSERR); 1178 }
| 947 if (prepare_commit(s->id) == -1) 948 goto fail; 949 prepared = 1;
|
1179
| 950
|
1180 debuglog(1, "local socket is %s:%u", OurName, 1181 ntohs(server_iob.sa.sin_port));
| 951 proxy_reply(s->cmd, orig_sa, s->proxy_port); 952 logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, linebuf);
|
1182
| 953
|
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)"); 1190 exit(EX_OSERR); 1191 }
| 954 /* rdr from $client to $orig_server port $proxy_port -> $server 955 port $port */ 956 if (add_rdr(s->id, client_sa, orig_sa, s->proxy_port, 957 server_sa, s->port) == -1) 958 goto fail;
|
1192
| 959
|
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)"); 1196 exit(EX_OSERR);
| 960 /* nat from $client to $server port $port -> $proxy */ 961 if (add_nat(s->id, client_sa, server_sa, s->port, proxy_sa, 962 PF_NAT_PROXY_PORT_LOW, PF_NAT_PROXY_PORT_HIGH) == -1) 963 goto fail; 964 965 /* pass in from $client to $server port $port */ 966 if (add_filter(s->id, PF_IN, client_sa, server_sa, 967 s->port) == -1) 968 goto fail; 969 970 /* pass out from $proxy to $server port $port */ 971 if (add_filter(s->id, PF_OUT, proxy_sa, server_sa, 972 s->port) == -1) 973 goto fail;
|
1197 } 1198
| 974 } 975
|
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;
| 976 /* Active modes. */ 977 if ((s->cmd == CMD_PORT || s->cmd == CMD_EPRT) && 978 strncmp("200 ", linebuf, 4) == 0) { 979 logmsg(LOG_INFO, "#%d active: server to client port %d" 980 " via port %d", s->id, s->port, s->proxy_port);
|
1209
| 981
|
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;
| 982 if (prepare_commit(s->id) == -1) 983 goto fail; 984 prepared = 1;
|
1220
| 985
|
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);
| 986 /* rdr from $server to $proxy port $proxy_port -> $client port 987 $port */ 988 if (add_rdr(s->id, server_sa, proxy_sa, s->proxy_port, 989 client_sa, s->port) == -1) 990 goto fail; 991 992 /* nat from $server to $client port $port -> $orig_server port 993 $natport */ 994 if (rfc_mode && s->cmd == CMD_PORT) { 995 /* Rewrite sourceport to RFC mandated 20. */ 996 if (add_nat(s->id, server_sa, client_sa, s->port, 997 orig_sa, 20, 20) == -1) 998 goto fail; 999 } else { 1000 /* Let pf pick a source port from the standard range. */ 1001 if (add_nat(s->id, server_sa, client_sa, s->port, 1002 orig_sa, PF_NAT_PROXY_PORT_LOW, 1003 PF_NAT_PROXY_PORT_HIGH) == -1) 1004 goto fail; 1005 } 1006 1007 /* pass in from $server to $client port $port */ 1008 if (add_filter(s->id, PF_IN, server_sa, client_sa, s->port) == 1009 -1) 1010 goto fail; 1011 1012 /* pass out from $orig_server to $client port $port */ 1013 if (add_filter(s->id, PF_OUT, orig_sa, client_sa, s->port) == 1014 -1) 1015 goto fail;
|
1225 } 1226
| 1016 } 1017
|
1227 while (client_iob.alive || server_iob.alive) { 1228 int maxfd = 0; 1229 fd_set *fdsp;
| 1018 /* Commit rules if they were prepared. */ 1019 if (prepared && (do_commit() == -1)) { 1020 if (errno != EBUSY) 1021 goto fail; 1022 /* One more try if busy. */ 1023 usleep(5000); 1024 if (do_commit() == -1) 1025 goto fail; 1026 }
|
1230
| 1027
|
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;
| 1028 out: 1029 s->cmd = CMD_NONE; 1030 s->port = 0;
|
1243
| 1031
|
1244 debuglog(3, "client is %s; server is %s", 1245 client_iob.alive ? "alive" : "dead", 1246 server_iob.alive ? "alive" : "dead");
| 1032 return (1);
|
1247
| 1033
|
1248 fdsp = (fd_set *)calloc(howmany(maxfd + 1, NFDBITS), 1249 sizeof(fd_mask)); 1250 if (fdsp == NULL) { 1251 syslog(LOG_NOTICE, "insufficient memory"); 1252 exit(EX_UNAVAILABLE); 1253 }
| 1034 fail: 1035 logmsg(LOG_CRIT, "#%d pf operation failed: %s", s->id, strerror(errno)); 1036 if (prepared) 1037 do_rollback(); 1038 return (0); 1039} 1040 1041void 1042server_read(struct bufferevent *bufev, void *arg) 1043{ 1044 struct session *s = arg; 1045 size_t buf_avail, read; 1046 int n;
|
1254
| 1047
|
1255 if (client_iob.alive && telnet_getline(&client_iob, 1256 &server_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, 1262 &client_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); 1267 } else { 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); 1274 } 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); 1281 } 1282 tv.tv_sec = timeout_seconds; 1283 tv.tv_usec = 0;
| 1048 bufferevent_settimeout(bufev, timeout, 0);
|
1284
| 1049
|
1285 doselect: 1286 sval = select(maxfd + 1, fdsp, NULL, NULL, 1287 (tv.tv_sec == 0) ? NULL : &tv); 1288 if (sval == 0) { 1289 /* 1290 * This proxy has timed out. Expire it 1291 * quietly with an obituary in the syslogs 1292 * for any passing mourners. 1293 */ 1294 syslog(LOG_INFO, 1295 "timeout: no data for %ld seconds", 1296 timeout_seconds); 1297 exit(EX_OK); 1298 } 1299 if (sval == -1) { 1300 if (errno == EINTR || errno == EAGAIN) 1301 goto doselect; 1302 syslog(LOG_NOTICE, 1303 "select() failed (%m)"); 1304 exit(EX_OSERR); 1305 } 1306 if (client_data_socket >= 0 && 1307 FD_ISSET(client_data_socket, fdsp)) { 1308 int rval;
| 1050 do { 1051 buf_avail = sizeof s->sbuf - s->sbuf_valid; 1052 read = bufferevent_read(bufev, s->sbuf + s->sbuf_valid, 1053 buf_avail); 1054 s->sbuf_valid += read;
|
1309
| 1055
|
1310 debuglog(3, "transfer: client to server"); 1311 rval = xfer_data("client to server", 1312 client_data_socket, 1313 server_data_socket, 1314 client_iob.sa.sin_addr, 1315 real_server_sa.sin_addr); 1316 if (rval <= 0) { 1317 close_client_data(); 1318 close_server_data(); 1319 show_xfer_stats(); 1320 } else 1321 client_data_bytes += rval;
| 1056 while ((n = getline(s->sbuf, &s->sbuf_valid)) > 0) { 1057 logmsg(LOG_DEBUG, "#%d server: %s", s->id, linebuf); 1058 if (!server_parse(s)) { 1059 end_session(s); 1060 return;
|
1322 }
| 1061 }
|
1323 if (server_data_socket >= 0 && 1324 FD_ISSET(server_data_socket, fdsp)) { 1325 int rval;
| 1062 bufferevent_write(s->client_bufev, linebuf, linelen); 1063 }
|
1326
| 1064
|
1327 debuglog(3, "transfer: server to client"); 1328 rval = xfer_data("server to client", 1329 server_data_socket, 1330 client_data_socket, 1331 real_server_sa.sin_addr, 1332 client_iob.sa.sin_addr); 1333 if (rval <= 0) { 1334 close_client_data(); 1335 close_server_data(); 1336 show_xfer_stats(); 1337 } else 1338 server_data_bytes += rval; 1339 } 1340 if (server_listen_socket >= 0 && 1341 FD_ISSET(server_listen_socket, fdsp)) { 1342 connect_port_backchannel(); 1343 } 1344 if (client_listen_socket >= 0 && 1345 FD_ISSET(client_listen_socket, fdsp)) { 1346 connect_pasv_backchannel(); 1347 } 1348 if (client_iob.alive && 1349 FD_ISSET(client_iob.fd, fdsp)) { 1350 client_iob.data_available = 1; 1351 } 1352 if (server_iob.alive && 1353 FD_ISSET(server_iob.fd, fdsp)) { 1354 server_iob.data_available = 1; 1355 }
| 1065 if (n == -1) { 1066 logmsg(LOG_ERR, "#%d server reply too long or not" 1067 " clean", s->id); 1068 end_session(s); 1069 return;
|
1356 }
| 1070 }
|
1357 free(fdsp); 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; 1363 } 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; 1369 }
| 1071 } while (read == buf_avail); 1072} 1073 1074const char * 1075sock_ntop(struct sockaddr *sa) 1076{ 1077 static int n = 0; 1078 1079 /* Cycle to next buffer. */ 1080 n = (n + 1) % NTOP_BUFS; 1081 ntop_buf[n][0] = '\0'; 1082 1083 if (sa->sa_family == AF_INET) { 1084 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 1085 1086 return (inet_ntop(AF_INET, &sin->sin_addr, ntop_buf[n], 1087 sizeof ntop_buf[0]));
|
1370 } 1371
| 1088 } 1089
|
1372 if (Verbose) 1373 syslog(LOG_INFO, "session ended");
| 1090 if (sa->sa_family == AF_INET6) { 1091 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
|
1374
| 1092
|
1375 exit(EX_OK);
| 1093 return (inet_ntop(AF_INET6, &sin6->sin6_addr, ntop_buf[n], 1094 sizeof ntop_buf[0])); 1095 } 1096 1097 return (NULL);
|
1376}
| 1098}
|
| 1099 1100void 1101usage(void) 1102{ 1103 fprintf(stderr, "usage: %s [-6Adrv] [-a address] [-b address]" 1104 " [-D level] [-m maxsessions]\n [-P port]" 1105 " [-p port] [-q queue] [-R address] [-t timeout]\n", __progname); 1106 exit(1); 1107}
|
| |