Deleted Added
full compact
ftp-proxy.c (145840) ftp-proxy.c (171172)
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}