xref: /openbsd/usr.sbin/ftp-proxy/ftp-proxy.c (revision b7041c07)
1 /*	$OpenBSD: ftp-proxy.c,v 1.39 2021/10/24 21:24:18 deraadt Exp $ */
2 
3 /*
4  * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl>
5  *
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.
9  *
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.
17  */
18 
19 #include <sys/queue.h>
20 #include <sys/types.h>
21 #include <sys/time.h>
22 #include <sys/resource.h>
23 #include <sys/socket.h>
24 
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <net/if.h>
28 #include <net/pfvar.h>
29 
30 #include <err.h>
31 #include <errno.h>
32 #include <event.h>
33 #include <fcntl.h>
34 #include <netdb.h>
35 #include <paths.h>
36 #include <pwd.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <syslog.h>
43 #include <unistd.h>
44 #include <vis.h>
45 
46 #include "filter.h"
47 
48 #define CONNECT_TIMEOUT	30
49 #define MIN_PORT	1024
50 #define MAX_LINE	500
51 #define MAX_LOGLINE	300
52 #define NTOP_BUFS	3
53 #define TCP_BACKLOG	10
54 
55 #define CHROOT_DIR	"/var/empty"
56 #define NOPRIV_USER	"_ftp_proxy"
57 
58 /* pfctl standard NAT range. */
59 #define PF_NAT_PROXY_PORT_LOW	50001
60 #define PF_NAT_PROXY_PORT_HIGH	65535
61 
62 #define	sstosa(ss)	((struct sockaddr *)(ss))
63 
64 enum { CMD_NONE = 0, CMD_PORT, CMD_EPRT, CMD_PASV, CMD_EPSV };
65 
66 struct session {
67 	u_int32_t		 id;
68 	struct sockaddr_storage  client_ss;
69 	struct sockaddr_storage  proxy_ss;
70 	struct sockaddr_storage  server_ss;
71 	struct sockaddr_storage  orig_server_ss;
72 	struct bufferevent	*client_bufev;
73 	struct bufferevent	*server_bufev;
74 	int			 client_fd;
75 	int			 server_fd;
76 	char			 cbuf[MAX_LINE];
77 	size_t			 cbuf_valid;
78 	char			 sbuf[MAX_LINE];
79 	size_t			 sbuf_valid;
80 	int			 cmd;
81 	int			 client_rd;
82 	u_int16_t		 port;
83 	u_int16_t		 proxy_port;
84 	LIST_ENTRY(session)	 entry;
85 };
86 
87 LIST_HEAD(, session) sessions = LIST_HEAD_INITIALIZER(sessions);
88 
89 void	client_error(struct bufferevent *, short, void *);
90 int	client_parse(struct session *s);
91 int	client_parse_anon(struct session *s);
92 int	client_parse_cmd(struct session *s);
93 void	client_read(struct bufferevent *, void *);
94 int	drop_privs(void);
95 void	end_session(struct session *);
96 void	exit_daemon(void);
97 int	get_line(char *, size_t *);
98 void	handle_connection(const int, short, void *);
99 void	handle_signal(int, short, void *);
100 struct session * init_session(void);
101 void	logmsg(int, const char *, ...);
102 u_int16_t parse_port(int);
103 u_int16_t pick_proxy_port(void);
104 void	proxy_reply(int, struct sockaddr *, u_int16_t);
105 int	rdaemon(int);
106 void	server_error(struct bufferevent *, short, void *);
107 int	server_parse(struct session *s);
108 int	allow_data_connection(struct session *s);
109 void	server_read(struct bufferevent *, void *);
110 const char *sock_ntop(struct sockaddr *);
111 void	usage(void);
112 
113 char linebuf[MAX_LINE + 1];
114 size_t linelen;
115 
116 char ntop_buf[NTOP_BUFS][INET6_ADDRSTRLEN];
117 
118 struct event listen_ev, pause_accept_ev;
119 struct sockaddr_storage fixed_server_ss, fixed_proxy_ss;
120 char *fixed_server, *fixed_server_port, *fixed_proxy, *listen_ip, *listen_port,
121     *qname, *tagname;
122 int anonymous_only, daemonize, id_count, ipv6_mode, loglevel, max_sessions,
123     rfc_mode, session_count, timeout, verbose;
124 extern char *__progname;
125 
126 void
client_error(struct bufferevent * bufev,short what,void * arg)127 client_error(struct bufferevent *bufev, short what, void *arg)
128 {
129 	struct session *s = arg;
130 
131 	if (what & EVBUFFER_EOF)
132 		logmsg(LOG_INFO, "#%d client close", s->id);
133 	else if (what == (EVBUFFER_ERROR | EVBUFFER_READ))
134 		logmsg(LOG_ERR, "#%d client reset connection", s->id);
135 	else if (what & EVBUFFER_TIMEOUT)
136 		logmsg(LOG_ERR, "#%d client timeout", s->id);
137 	else if (what & EVBUFFER_WRITE)
138 		logmsg(LOG_ERR, "#%d client write error: %d", s->id, what);
139 	else
140 		logmsg(LOG_ERR, "#%d abnormal client error: %d", s->id, what);
141 
142 	end_session(s);
143 }
144 
145 int
client_parse(struct session * s)146 client_parse(struct session *s)
147 {
148 	/* Reset any previous command. */
149 	s->cmd = CMD_NONE;
150 	s->port = 0;
151 
152 	/* Commands we are looking for are at least 4 chars long. */
153 	if (linelen < 4)
154 		return (1);
155 
156 	if (linebuf[0] == 'P' || linebuf[0] == 'p' ||
157 	    linebuf[0] == 'E' || linebuf[0] == 'e') {
158 		if (!client_parse_cmd(s))
159 			return (0);
160 
161 		/*
162 		 * Allow active mode connections immediately, instead of
163 		 * waiting for a positive reply from the server.  Some
164 		 * rare servers/proxies try to probe or setup the data
165 		 * connection before an actual transfer request.
166 		 */
167 		if (s->cmd == CMD_PORT || s->cmd == CMD_EPRT)
168 			return (allow_data_connection(s));
169 	}
170 
171 	if (anonymous_only && (linebuf[0] == 'U' || linebuf[0] == 'u'))
172 		return (client_parse_anon(s));
173 
174 	return (1);
175 }
176 
177 int
client_parse_anon(struct session * s)178 client_parse_anon(struct session *s)
179 {
180 	if (strcasecmp("USER ftp\r\n", linebuf) != 0 &&
181 	    strcasecmp("USER anonymous\r\n", linebuf) != 0) {
182 		snprintf(linebuf, sizeof linebuf,
183 		    "500 Only anonymous FTP allowed\r\n");
184 		logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, linebuf);
185 
186 		/* Talk back to the client ourself. */
187 		linelen = strlen(linebuf);
188 		bufferevent_write(s->client_bufev, linebuf, linelen);
189 
190 		/* Clear buffer so it's not sent to the server. */
191 		linebuf[0] = '\0';
192 		linelen = 0;
193 	}
194 
195 	return (1);
196 }
197 
198 int
client_parse_cmd(struct session * s)199 client_parse_cmd(struct session *s)
200 {
201 	if (strncasecmp("PASV", linebuf, 4) == 0)
202 		s->cmd = CMD_PASV;
203 	else if (strncasecmp("PORT ", linebuf, 5) == 0)
204 		s->cmd = CMD_PORT;
205 	else if (strncasecmp("EPSV", linebuf, 4) == 0)
206 		s->cmd = CMD_EPSV;
207 	else if (strncasecmp("EPRT ", linebuf, 5) == 0)
208 		s->cmd = CMD_EPRT;
209 	else
210 		return (1);
211 
212 	if (ipv6_mode && (s->cmd == CMD_PASV || s->cmd == CMD_PORT)) {
213 		logmsg(LOG_CRIT, "PASV and PORT not allowed with IPv6");
214 		return (0);
215 	}
216 
217 	if (s->cmd == CMD_PORT || s->cmd == CMD_EPRT) {
218 		s->port = parse_port(s->cmd);
219 		if (s->port < MIN_PORT) {
220 			logmsg(LOG_CRIT, "#%d bad port in '%s'", s->id,
221 			    linebuf);
222 			return (0);
223 		}
224 		s->proxy_port = pick_proxy_port();
225 		proxy_reply(s->cmd, sstosa(&s->proxy_ss), s->proxy_port);
226 		logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, linebuf);
227 	}
228 
229 	return (1);
230 }
231 
232 void
client_read(struct bufferevent * bufev,void * arg)233 client_read(struct bufferevent *bufev, void *arg)
234 {
235 	struct session	*s = arg;
236 	size_t		 buf_avail, read;
237 	int		 n;
238 
239 	do {
240 		buf_avail = sizeof s->cbuf - s->cbuf_valid;
241 		read = bufferevent_read(bufev, s->cbuf + s->cbuf_valid,
242 		    buf_avail);
243 		s->cbuf_valid += read;
244 
245 		while ((n = get_line(s->cbuf, &s->cbuf_valid)) > 0) {
246 			logmsg(LOG_DEBUG, "#%d client: %s", s->id, linebuf);
247 			if (!client_parse(s)) {
248 				end_session(s);
249 				return;
250 			}
251 			bufferevent_write(s->server_bufev, linebuf, linelen);
252 		}
253 
254 		if (n == -1) {
255 			logmsg(LOG_ERR, "#%d client command too long or not"
256 			    " clean", s->id);
257 			end_session(s);
258 			return;
259 		}
260 	} while (read == buf_avail);
261 }
262 
263 int
drop_privs(void)264 drop_privs(void)
265 {
266 	struct passwd *pw;
267 
268 	pw = getpwnam(NOPRIV_USER);
269 	if (pw == NULL)
270 		return (0);
271 
272 	tzset();
273 	if (chroot(CHROOT_DIR) != 0 || chdir("/") != 0 ||
274 	    setgroups(1, &pw->pw_gid) != 0 ||
275 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0 ||
276 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0)
277 		return (0);
278 
279 	return (1);
280 }
281 
282 void
end_session(struct session * s)283 end_session(struct session *s)
284 {
285 	int err;
286 
287 	logmsg(LOG_INFO, "#%d ending session", s->id);
288 
289 	/* Flush output buffers. */
290 	if (s->client_bufev && s->client_fd != -1)
291 		evbuffer_write(s->client_bufev->output, s->client_fd);
292 	if (s->server_bufev && s->server_fd != -1)
293 		evbuffer_write(s->server_bufev->output, s->server_fd);
294 
295 	if (s->client_fd != -1)
296 		close(s->client_fd);
297 	if (s->server_fd != -1)
298 		close(s->server_fd);
299 
300 	if (s->client_bufev)
301 		bufferevent_free(s->client_bufev);
302 	if (s->server_bufev)
303 		bufferevent_free(s->server_bufev);
304 
305 	/* Remove rulesets by committing empty ones. */
306 	err = 0;
307 	if (prepare_commit(s->id) == -1)
308 		err = errno;
309 	else if (do_commit() == -1) {
310 		err = errno;
311 		do_rollback();
312 	}
313 	if (err)
314 		logmsg(LOG_ERR, "#%d pf rule removal failed: %s", s->id,
315 		    strerror(err));
316 
317 	LIST_REMOVE(s, entry);
318 	free(s);
319 	session_count--;
320 }
321 
322 void
exit_daemon(void)323 exit_daemon(void)
324 {
325 	struct session *s, *next;
326 
327 	for (s = LIST_FIRST(&sessions); s != NULL; s = next) {
328 		next = LIST_NEXT(s, entry);
329 		end_session(s);
330 	}
331 
332 	if (daemonize)
333 		closelog();
334 
335 	exit(0);
336 }
337 
338 int
get_line(char * buf,size_t * valid)339 get_line(char *buf, size_t *valid)
340 {
341 	size_t i;
342 
343 	if (*valid > MAX_LINE)
344 		return (-1);
345 
346 	/* Copy to linebuf while searching for a newline. */
347 	for (i = 0; i < *valid; i++) {
348 		linebuf[i] = buf[i];
349 		if (buf[i] == '\0')
350 			return (-1);
351 		if (buf[i] == '\n')
352 			break;
353 	}
354 
355 	if (i == *valid) {
356 		/* No newline found. */
357 		linebuf[0] = '\0';
358 		linelen = 0;
359 		if (i < MAX_LINE)
360 			return (0);
361 		return (-1);
362 	}
363 
364 	linelen = i + 1;
365 	linebuf[linelen] = '\0';
366 	*valid -= linelen;
367 
368 	/* Move leftovers to the start. */
369 	if (*valid != 0)
370 		bcopy(buf + linelen, buf, *valid);
371 
372 	return ((int)linelen);
373 }
374 
375 void
handle_connection(const int listen_fd,short event,void * arg)376 handle_connection(const int listen_fd, short event, void *arg)
377 {
378 	struct sockaddr_storage tmp_ss;
379 	struct sockaddr *client_sa, *server_sa, *fixed_server_sa;
380 	struct sockaddr *proxy_to_server_sa;
381 	struct session *s;
382 	socklen_t len;
383 	int client_fd, fc, on;
384 
385 	event_add(&listen_ev, NULL);
386 
387 	if ((event & EV_TIMEOUT))
388 		/* accept() is no longer paused. */
389 		return;
390 
391 	/*
392 	 * We _must_ accept the connection, otherwise libevent will keep
393 	 * coming back, and we will chew up all CPU.
394 	 */
395 	client_sa = sstosa(&tmp_ss);
396 	len = sizeof(struct sockaddr_storage);
397 	if ((client_fd = accept(listen_fd, client_sa, &len)) == -1) {
398 		logmsg(LOG_CRIT, "accept() failed: %s", strerror(errno));
399 
400 		/*
401 		 * Pause accept if we are out of file descriptors, or
402 		 * libevent will haunt us here too.
403 		 */
404 		if (errno == ENFILE || errno == EMFILE) {
405 			struct timeval pause = { 1, 0 };
406 
407 			event_del(&listen_ev);
408 			evtimer_add(&pause_accept_ev, &pause);
409 		} else if (errno != EWOULDBLOCK && errno != EINTR &&
410 		    errno != ECONNABORTED)
411 			logmsg(LOG_CRIT, "accept() failed: %s", strerror(errno));
412 		return;
413 	}
414 
415 	/* Refuse connection if the maximum is reached. */
416 	if (session_count >= max_sessions) {
417 		logmsg(LOG_ERR, "client limit (%d) reached, refusing "
418 		    "connection from %s", max_sessions, sock_ntop(client_sa));
419 		close(client_fd);
420 		return;
421 	}
422 
423 	/* Allocate session and copy back the info from the accept(). */
424 	s = init_session();
425 	if (s == NULL) {
426 		logmsg(LOG_CRIT, "init_session failed");
427 		close(client_fd);
428 		return;
429 	}
430 	s->client_fd = client_fd;
431 	memcpy(sstosa(&s->client_ss), client_sa, client_sa->sa_len);
432 
433 	/* Cast it once, and be done with it. */
434 	client_sa = sstosa(&s->client_ss);
435 	server_sa = sstosa(&s->server_ss);
436 	proxy_to_server_sa = sstosa(&s->proxy_ss);
437 	fixed_server_sa = sstosa(&fixed_server_ss);
438 
439 	/* Log id/client early to ease debugging. */
440 	logmsg(LOG_DEBUG, "#%d accepted connection from %s", s->id,
441 	    sock_ntop(client_sa));
442 
443 	/*
444 	 * Find out the real server and port that the client wanted.
445 	 */
446 	len = sizeof(struct sockaddr_storage);
447 	if (getsockname(s->client_fd, server_sa, &len) == -1) {
448 		logmsg(LOG_CRIT, "#%d getsockname failed: %s", s->id,
449 		    strerror(errno));
450 		goto fail;
451 	}
452 	len = sizeof(s->client_rd);
453 	if (getsockopt(s->client_fd, SOL_SOCKET, SO_RTABLE, &s->client_rd,
454 	    &len) && errno != ENOPROTOOPT) {
455 		logmsg(LOG_CRIT, "#%d getsockopt failed: %s", s->id,
456 		    strerror(errno));
457 		goto fail;
458 	}
459 	if (fixed_server) {
460 		memcpy(sstosa(&s->orig_server_ss), server_sa,
461 		    server_sa->sa_len);
462 		memcpy(server_sa, fixed_server_sa, fixed_server_sa->sa_len);
463 	}
464 
465 	/* XXX: check we are not connecting to ourself. */
466 
467 	/*
468 	 * Setup socket and connect to server.
469 	 */
470 	if ((s->server_fd = socket(server_sa->sa_family, SOCK_STREAM,
471 	    IPPROTO_TCP)) == -1) {
472 		logmsg(LOG_CRIT, "#%d server socket failed: %s", s->id,
473 		    strerror(errno));
474 		goto fail;
475 	}
476 	if (fixed_proxy && bind(s->server_fd, sstosa(&fixed_proxy_ss),
477 	    fixed_proxy_ss.ss_len) != 0) {
478 		logmsg(LOG_CRIT, "#%d cannot bind fixed proxy address: %s",
479 		    s->id, strerror(errno));
480 		goto fail;
481 	}
482 
483 	/* Use non-blocking connect(), see CONNECT_TIMEOUT below. */
484 	if ((fc = fcntl(s->server_fd, F_GETFL)) == -1 ||
485 	    fcntl(s->server_fd, F_SETFL, fc | O_NONBLOCK) == -1) {
486 		logmsg(LOG_CRIT, "#%d cannot mark socket non-blocking: %s",
487 		    s->id, strerror(errno));
488 		goto fail;
489 	}
490 	if (connect(s->server_fd, server_sa, server_sa->sa_len) == -1 &&
491 	    errno != EINPROGRESS) {
492 		logmsg(LOG_CRIT, "#%d proxy cannot connect to server %s: %s",
493 		    s->id, sock_ntop(server_sa), strerror(errno));
494 		goto fail;
495 	}
496 
497 	len = sizeof(struct sockaddr_storage);
498 	if ((getsockname(s->server_fd, proxy_to_server_sa, &len)) == -1) {
499 		logmsg(LOG_CRIT, "#%d getsockname failed: %s", s->id,
500 		    strerror(errno));
501 		goto fail;
502 	}
503 
504 	logmsg(LOG_INFO, "#%d FTP session %d/%d started: client %s to server "
505 	    "%s via proxy %s", s->id, session_count, max_sessions,
506 	    sock_ntop(client_sa), sock_ntop(server_sa),
507 	    sock_ntop(proxy_to_server_sa));
508 
509 	/* Keepalive is nice, but don't care if it fails. */
510 	on = 1;
511 	setsockopt(s->client_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
512 	    sizeof on);
513 	setsockopt(s->server_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
514 	    sizeof on);
515 
516 	/*
517 	 * Setup buffered events.
518 	 */
519 	s->client_bufev = bufferevent_new(s->client_fd, &client_read, NULL,
520 	    &client_error, s);
521 	if (s->client_bufev == NULL) {
522 		logmsg(LOG_CRIT, "#%d bufferevent_new client failed", s->id);
523 		goto fail;
524 	}
525 	bufferevent_settimeout(s->client_bufev, timeout, 0);
526 	bufferevent_enable(s->client_bufev, EV_READ | EV_TIMEOUT);
527 
528 	s->server_bufev = bufferevent_new(s->server_fd, &server_read, NULL,
529 	    &server_error, s);
530 	if (s->server_bufev == NULL) {
531 		logmsg(LOG_CRIT, "#%d bufferevent_new server failed", s->id);
532 		goto fail;
533 	}
534 	bufferevent_settimeout(s->server_bufev, CONNECT_TIMEOUT, 0);
535 	bufferevent_enable(s->server_bufev, EV_READ | EV_TIMEOUT);
536 
537 	return;
538 
539  fail:
540 	end_session(s);
541 }
542 
543 void
handle_signal(int sig,short event,void * arg)544 handle_signal(int sig, short event, void *arg)
545 {
546 	/*
547 	 * Signal handler rules don't apply, libevent decouples for us.
548 	 */
549 
550 	logmsg(LOG_ERR, "exiting on signal %d", sig);
551 
552 	exit_daemon();
553 }
554 
555 
556 struct session *
init_session(void)557 init_session(void)
558 {
559 	struct session *s;
560 
561 	s = calloc(1, sizeof(struct session));
562 	if (s == NULL)
563 		return (NULL);
564 
565 	s->id = id_count++;
566 	s->client_fd = -1;
567 	s->server_fd = -1;
568 	s->cbuf[0] = '\0';
569 	s->cbuf_valid = 0;
570 	s->sbuf[0] = '\0';
571 	s->sbuf_valid = 0;
572 	s->client_bufev = NULL;
573 	s->server_bufev = NULL;
574 	s->cmd = CMD_NONE;
575 	s->port = 0;
576 
577 	LIST_INSERT_HEAD(&sessions, s, entry);
578 	session_count++;
579 
580 	return (s);
581 }
582 
583 void
logmsg(int pri,const char * message,...)584 logmsg(int pri, const char *message, ...)
585 {
586 	va_list	ap;
587 
588 	if (pri > loglevel)
589 		return;
590 
591 	va_start(ap, message);
592 
593 	if (daemonize)
594 		/* syslog does its own vissing. */
595 		vsyslog(pri, message, ap);
596 	else {
597 		char buf[MAX_LOGLINE];
598 		char visbuf[2 * MAX_LOGLINE];
599 
600 		/* We don't care about truncation. */
601 		vsnprintf(buf, sizeof buf, message, ap);
602 		strnvis(visbuf, buf, sizeof visbuf, VIS_CSTYLE | VIS_NL);
603 		fprintf(stderr, "%s\n", visbuf);
604 	}
605 
606 	va_end(ap);
607 }
608 
609 int
main(int argc,char * argv[])610 main(int argc, char *argv[])
611 {
612 	struct rlimit rlp;
613 	struct addrinfo hints, *res;
614 	struct event ev_sighup, ev_sigint, ev_sigterm;
615 	int ch, devnull, error, listenfd, on;
616 	const char *errstr;
617 
618 	/* Defaults. */
619 	anonymous_only	= 0;
620 	daemonize	= 1;
621 	fixed_proxy	= NULL;
622 	fixed_server	= NULL;
623 	fixed_server_port = "21";
624 	ipv6_mode	= 0;
625 	listen_ip	= NULL;
626 	listen_port	= "8021";
627 	loglevel	= LOG_NOTICE;
628 	max_sessions	= 100;
629 	qname		= NULL;
630 	rfc_mode	= 0;
631 	tagname		= NULL;
632 	timeout		= 24 * 3600;
633 	verbose		= 0;
634 
635 	/* Other initialization. */
636 	devnull		= -1;
637 	id_count	= 1;
638 	session_count	= 0;
639 
640 	while ((ch = getopt(argc, argv, "6Aa:b:D:dm:P:p:q:R:rT:t:v")) != -1) {
641 		switch (ch) {
642 		case '6':
643 			ipv6_mode = 1;
644 			break;
645 		case 'A':
646 			anonymous_only = 1;
647 			break;
648 		case 'a':
649 			fixed_proxy = optarg;
650 			break;
651 		case 'b':
652 			listen_ip = optarg;
653 			break;
654 		case 'D':
655 			loglevel = strtonum(optarg, LOG_EMERG, LOG_DEBUG,
656 			    &errstr);
657 			if (errstr)
658 				errx(1, "loglevel %s", errstr);
659 			break;
660 		case 'd':
661 			daemonize = 0;
662 			break;
663 		case 'm':
664 			max_sessions = strtonum(optarg, 1, 500, &errstr);
665 			if (errstr)
666 				errx(1, "max sessions %s", errstr);
667 			break;
668 		case 'P':
669 			fixed_server_port = optarg;
670 			break;
671 		case 'p':
672 			listen_port = optarg;
673 			break;
674 		case 'q':
675 			if (strlen(optarg) >= PF_QNAME_SIZE)
676 				errx(1, "queuename too long");
677 			qname = optarg;
678 			break;
679 		case 'R':
680 			fixed_server = optarg;
681 			break;
682 		case 'r':
683 			rfc_mode = 1;
684 			break;
685 		case 'T':
686 			if (strlen(optarg) >= PF_TAG_NAME_SIZE)
687 				errx(1, "tagname too long");
688 			tagname = optarg;
689 			break;
690 		case 't':
691 			timeout = strtonum(optarg, 0, 86400, &errstr);
692 			if (errstr)
693 				errx(1, "timeout %s", errstr);
694 			break;
695 		case 'v':
696 			verbose++;
697 			if (verbose > 2)
698 				usage();
699 			break;
700 		default:
701 			usage();
702 		}
703 	}
704 
705 	if (listen_ip == NULL)
706 		listen_ip = ipv6_mode ? "::1" : "127.0.0.1";
707 
708 	/* Check for root to save the user from cryptic failure messages. */
709 	if (getuid() != 0)
710 		errx(1, "needs to start as root");
711 
712 	if (getpwnam(NOPRIV_USER) == NULL)
713 		errx(1, "unknown user %s", NOPRIV_USER);
714 
715 	/* Raise max. open files limit to satisfy max. sessions. */
716 	rlp.rlim_cur = rlp.rlim_max = (2 * max_sessions) + 10;
717 	if (setrlimit(RLIMIT_NOFILE, &rlp) == -1)
718 		err(1, "setrlimit");
719 
720 	if (fixed_proxy) {
721 		memset(&hints, 0, sizeof hints);
722 		hints.ai_flags = AI_NUMERICHOST;
723 		hints.ai_family = ipv6_mode ? AF_INET6 : AF_INET;
724 		hints.ai_socktype = SOCK_STREAM;
725 		error = getaddrinfo(fixed_proxy, NULL, &hints, &res);
726 		if (error)
727 			errx(1, "getaddrinfo fixed proxy address failed: %s",
728 			    gai_strerror(error));
729 		memcpy(&fixed_proxy_ss, res->ai_addr, res->ai_addrlen);
730 		logmsg(LOG_INFO, "using %s to connect to servers",
731 		    sock_ntop(sstosa(&fixed_proxy_ss)));
732 		freeaddrinfo(res);
733 	}
734 
735 	if (fixed_server) {
736 		memset(&hints, 0, sizeof hints);
737 		hints.ai_family = ipv6_mode ? AF_INET6 : AF_INET;
738 		hints.ai_socktype = SOCK_STREAM;
739 		error = getaddrinfo(fixed_server, fixed_server_port, &hints,
740 		    &res);
741 		if (error)
742 			errx(1, "getaddrinfo fixed server address failed: %s",
743 			    gai_strerror(error));
744 		memcpy(&fixed_server_ss, res->ai_addr, res->ai_addrlen);
745 		logmsg(LOG_INFO, "using fixed server %s",
746 		    sock_ntop(sstosa(&fixed_server_ss)));
747 		freeaddrinfo(res);
748 	}
749 
750 	/* Setup listener. */
751 	memset(&hints, 0, sizeof hints);
752 	hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
753 	hints.ai_family = ipv6_mode ? AF_INET6 : AF_INET;
754 	hints.ai_socktype = SOCK_STREAM;
755 	error = getaddrinfo(listen_ip, listen_port, &hints, &res);
756 	if (error)
757 		errx(1, "getaddrinfo listen address failed: %s",
758 		    gai_strerror(error));
759 	if ((listenfd = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
760 		errx(1, "socket failed");
761 	on = 1;
762 	if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
763 	    sizeof on) != 0)
764 		err(1, "setsockopt failed");
765 	if (bind(listenfd, (struct sockaddr *)res->ai_addr,
766 	    (socklen_t)res->ai_addrlen) != 0)
767 	    	err(1, "bind failed");
768 	if (listen(listenfd, TCP_BACKLOG) != 0)
769 		err(1, "listen failed");
770 	freeaddrinfo(res);
771 
772 	/* Initialize pf. */
773 	init_filter(qname, tagname, verbose);
774 
775 	if (daemonize) {
776 		devnull = open(_PATH_DEVNULL, O_RDWR);
777 		if (devnull == -1)
778 			err(1, "open(%s)", _PATH_DEVNULL);
779 	}
780 
781 	if (!drop_privs())
782 		err(1, "cannot drop privileges");
783 
784 	if (daemonize) {
785 		if (rdaemon(devnull) == -1)
786 			err(1, "cannot daemonize");
787 		openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
788 	}
789 
790 	/* Use logmsg for output from here on. */
791 
792 	event_init();
793 
794 	/* Setup signal handler. */
795 	signal(SIGPIPE, SIG_IGN);
796 	signal_set(&ev_sighup, SIGHUP, handle_signal, NULL);
797 	signal_set(&ev_sigint, SIGINT, handle_signal, NULL);
798 	signal_set(&ev_sigterm, SIGTERM, handle_signal, NULL);
799 	signal_add(&ev_sighup, NULL);
800 	signal_add(&ev_sigint, NULL);
801 	signal_add(&ev_sigterm, NULL);
802 
803 	event_set(&listen_ev, listenfd, EV_READ, handle_connection, NULL);
804 	event_add(&listen_ev, NULL);
805 	evtimer_set(&pause_accept_ev, handle_connection, NULL);
806 
807 	logmsg(LOG_NOTICE, "listening on %s port %s", listen_ip, listen_port);
808 
809 	/*  Vroom, vroom.  */
810 	event_dispatch();
811 
812 	logmsg(LOG_ERR, "event_dispatch error: %s", strerror(errno));
813 	exit_daemon();
814 
815 	/* NOTREACHED */
816 	return (1);
817 }
818 
819 u_int16_t
parse_port(int mode)820 parse_port(int mode)
821 {
822 	unsigned int	 port, v[6];
823 	int		 n;
824 	char		*p;
825 
826 	/* Find the last space or left-parenthesis. */
827 	for (p = linebuf + linelen; p > linebuf; p--)
828 		if (*p == ' ' || *p == '(')
829 			break;
830 	if (p == linebuf)
831 		return (0);
832 
833 	switch (mode) {
834 	case CMD_PORT:
835 		n = sscanf(p, " %u,%u,%u,%u,%u,%u", &v[0], &v[1], &v[2],
836 		    &v[3], &v[4], &v[5]);
837 		if (n == 6 && v[0] < 256 && v[1] < 256 && v[2] < 256 &&
838 		    v[3] < 256 && v[4] < 256 && v[5] < 256)
839 			return ((v[4] << 8) | v[5]);
840 		break;
841 	case CMD_PASV:
842 		n = sscanf(p, "(%u,%u,%u,%u,%u,%u)", &v[0], &v[1], &v[2],
843 		    &v[3], &v[4], &v[5]);
844 		if (n == 6 && v[0] < 256 && v[1] < 256 && v[2] < 256 &&
845 		    v[3] < 256 && v[4] < 256 && v[5] < 256)
846 			return ((v[4] << 8) | v[5]);
847 		break;
848 	case CMD_EPSV:
849 		n = sscanf(p, "(|||%u|)", &port);
850 		if (n == 1 && port < 65536)
851 			return (port);
852 		break;
853 	case CMD_EPRT:
854 		n = sscanf(p, " |1|%u.%u.%u.%u|%u|", &v[0], &v[1], &v[2],
855 		    &v[3], &port);
856 		if (n == 5 && v[0] < 256 && v[1] < 256 && v[2] < 256 &&
857 		    v[3] < 256 && port < 65536)
858 			return (port);
859 		n = sscanf(p, " |2|%*[a-fA-F0-9:]|%u|", &port);
860 		if (n == 1 && port < 65536)
861 			return (port);
862 		break;
863 	default:
864 		return (0);
865 	}
866 
867 	return (0);
868 }
869 
870 u_int16_t
pick_proxy_port(void)871 pick_proxy_port(void)
872 {
873 	/* Random should be good enough for avoiding port collisions. */
874 	return (IPPORT_HIFIRSTAUTO +
875 	    arc4random_uniform(IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO));
876 }
877 
878 void
proxy_reply(int cmd,struct sockaddr * sa,u_int16_t port)879 proxy_reply(int cmd, struct sockaddr *sa, u_int16_t port)
880 {
881 	int i, r;
882 
883 	switch (cmd) {
884 	case CMD_PORT:
885 		r = snprintf(linebuf, sizeof linebuf,
886 		    "PORT %s,%u,%u\r\n", sock_ntop(sa), port / 256,
887 		    port % 256);
888 		break;
889 	case CMD_PASV:
890 		r = snprintf(linebuf, sizeof linebuf,
891 		    "227 Entering Passive Mode (%s,%u,%u)\r\n", sock_ntop(sa),
892 		        port / 256, port % 256);
893 		break;
894 	case CMD_EPRT:
895 		if (sa->sa_family == AF_INET)
896 			r = snprintf(linebuf, sizeof linebuf,
897 			    "EPRT |1|%s|%u|\r\n", sock_ntop(sa), port);
898 		else if (sa->sa_family == AF_INET6)
899 			r = snprintf(linebuf, sizeof linebuf,
900 			    "EPRT |2|%s|%u|\r\n", sock_ntop(sa), port);
901 		break;
902 	case CMD_EPSV:
903 		r = snprintf(linebuf, sizeof linebuf,
904 		    "229 Entering Extended Passive Mode (|||%u|)\r\n", port);
905 		break;
906 	}
907 
908 	if (r == -1 || r >= sizeof linebuf) {
909 		logmsg(LOG_ERR, "proxy_reply failed: %d", r);
910 		linebuf[0] = '\0';
911 		linelen = 0;
912 		return;
913 	}
914 	linelen = (size_t)r;
915 
916 	if (cmd == CMD_PORT || cmd == CMD_PASV) {
917 		/* Replace dots in IP address with commas. */
918 		for (i = 0; i < linelen; i++)
919 			if (linebuf[i] == '.')
920 				linebuf[i] = ',';
921 	}
922 }
923 
924 void
server_error(struct bufferevent * bufev,short what,void * arg)925 server_error(struct bufferevent *bufev, short what, void *arg)
926 {
927 	struct session *s = arg;
928 
929 	if (what & EVBUFFER_EOF)
930 		logmsg(LOG_INFO, "#%d server close", s->id);
931 	else if (what == (EVBUFFER_ERROR | EVBUFFER_READ))
932 		logmsg(LOG_ERR, "#%d server refused connection", s->id);
933 	else if (what & EVBUFFER_WRITE)
934 		logmsg(LOG_ERR, "#%d server write error: %d", s->id, what);
935 	else if (what & EVBUFFER_TIMEOUT)
936 		logmsg(LOG_NOTICE, "#%d server timeout", s->id);
937 	else
938 		logmsg(LOG_ERR, "#%d abnormal server error: %d", s->id, what);
939 
940 	end_session(s);
941 }
942 
943 int
server_parse(struct session * s)944 server_parse(struct session *s)
945 {
946 	if (s->cmd == CMD_NONE || linelen < 4 || linebuf[0] != '2')
947 		goto out;
948 
949 	if ((s->cmd == CMD_PASV && strncmp("227 ", linebuf, 4) == 0) ||
950 	    (s->cmd == CMD_EPSV && strncmp("229 ", linebuf, 4) == 0))
951 		return (allow_data_connection(s));
952 
953  out:
954 	s->cmd = CMD_NONE;
955 	s->port = 0;
956 
957 	return (1);
958 }
959 
960 int
allow_data_connection(struct session * s)961 allow_data_connection(struct session *s)
962 {
963 	struct sockaddr *client_sa, *orig_sa, *proxy_sa, *server_sa;
964 	int prepared = 0;
965 
966 	/*
967 	 * The pf rules below do quite some NAT rewriting, to keep up
968 	 * appearances.  Points to keep in mind:
969 	 * 1)  The client must think it's talking to the real server,
970 	 *     for both control and data connections.  Transparently.
971 	 * 2)  The server must think that the proxy is the client.
972 	 * 3)  Source and destination ports are rewritten to minimize
973 	 *     port collisions, to aid security (some systems pick weak
974 	 *     ports) or to satisfy RFC requirements (source port 20).
975 	 */
976 
977 	/* Cast this once, to make code below it more readable. */
978 	client_sa = sstosa(&s->client_ss);
979 	server_sa = sstosa(&s->server_ss);
980 	proxy_sa = sstosa(&s->proxy_ss);
981 	if (fixed_server)
982 		/* Fixed server: data connections must appear to come
983 		   from / go to the original server, not the fixed one. */
984 		orig_sa = sstosa(&s->orig_server_ss);
985 	else
986 		/* Server not fixed: orig_server == server. */
987 		orig_sa = sstosa(&s->server_ss);
988 
989 	/* Passive modes. */
990 	if (s->cmd == CMD_PASV || s->cmd == CMD_EPSV) {
991 		s->port = parse_port(s->cmd);
992 		if (s->port < MIN_PORT) {
993 			logmsg(LOG_CRIT, "#%d bad port in '%s'", s->id,
994 			    linebuf);
995 			return (0);
996 		}
997 		s->proxy_port = pick_proxy_port();
998 		logmsg(LOG_INFO, "#%d passive: client to server port %d"
999 		    " via port %d", s->id, s->port, s->proxy_port);
1000 
1001 		if (prepare_commit(s->id) == -1)
1002 			goto fail;
1003 		prepared = 1;
1004 
1005 		proxy_reply(s->cmd, orig_sa, s->proxy_port);
1006 		logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, linebuf);
1007 
1008 		/* pass in from $client to $orig_server port $proxy_port
1009 		    rdr-to $server port $port */
1010 		if (add_rdr(s->id, client_sa, s->client_rd, orig_sa,
1011 		    s->proxy_port, server_sa, s->port, getrtable()) == -1)
1012 			goto fail;
1013 
1014 		/* pass out from $client to $server port $port nat-to $proxy */
1015 		if (add_nat(s->id, client_sa, getrtable(), server_sa,
1016 		    s->port, proxy_sa, PF_NAT_PROXY_PORT_LOW,
1017 		    PF_NAT_PROXY_PORT_HIGH) == -1)
1018 			goto fail;
1019 	}
1020 
1021 	/* Active modes. */
1022 	if (s->cmd == CMD_PORT || s->cmd == CMD_EPRT) {
1023 		logmsg(LOG_INFO, "#%d active: server to client port %d"
1024 		    " via port %d", s->id, s->port, s->proxy_port);
1025 
1026 		if (prepare_commit(s->id) == -1)
1027 			goto fail;
1028 		prepared = 1;
1029 
1030 		/* pass in from $server to $proxy port $proxy_port
1031 		    rdr-to $client port $port */
1032 		if (add_rdr(s->id, server_sa, getrtable(), proxy_sa,
1033 		    s->proxy_port, client_sa, s->port, s->client_rd) == -1)
1034 			goto fail;
1035 
1036 		/* pass out from $server to $client port $port
1037 		    nat-to $orig_server port $natport */
1038 		if (rfc_mode && s->cmd == CMD_PORT) {
1039 			/* Rewrite sourceport to RFC mandated 20. */
1040 			if (add_nat(s->id, server_sa, s->client_rd, client_sa,
1041 			    s->port, orig_sa, 20, 20) == -1)
1042 				goto fail;
1043 		} else {
1044 			/* Let pf pick a source port from the standard range. */
1045 			if (add_nat(s->id, server_sa, s->client_rd, client_sa,
1046 			    s->port, orig_sa, PF_NAT_PROXY_PORT_LOW,
1047 			    PF_NAT_PROXY_PORT_HIGH) == -1)
1048 			    	goto fail;
1049 		}
1050 	}
1051 
1052 	/* Commit rules if they were prepared. */
1053 	if (prepared && (do_commit() == -1)) {
1054 		if (errno != EBUSY)
1055 			goto fail;
1056 		/* One more try if busy. */
1057 		usleep(5000);
1058 		if (do_commit() == -1)
1059 			goto fail;
1060 	}
1061 
1062 	s->cmd = CMD_NONE;
1063 	s->port = 0;
1064 
1065 	return (1);
1066 
1067  fail:
1068 	logmsg(LOG_CRIT, "#%d pf operation failed: %s", s->id, strerror(errno));
1069 	if (prepared)
1070 		do_rollback();
1071 	return (0);
1072 }
1073 
1074 void
server_read(struct bufferevent * bufev,void * arg)1075 server_read(struct bufferevent *bufev, void *arg)
1076 {
1077 	struct session	*s = arg;
1078 	size_t		 buf_avail, read;
1079 	int		 n;
1080 
1081 	bufferevent_settimeout(bufev, timeout, 0);
1082 
1083 	do {
1084 		buf_avail = sizeof s->sbuf - s->sbuf_valid;
1085 		read = bufferevent_read(bufev, s->sbuf + s->sbuf_valid,
1086 		    buf_avail);
1087 		s->sbuf_valid += read;
1088 
1089 		while ((n = get_line(s->sbuf, &s->sbuf_valid)) > 0) {
1090 			logmsg(LOG_DEBUG, "#%d server: %s", s->id, linebuf);
1091 			if (!server_parse(s)) {
1092 				end_session(s);
1093 				return;
1094 			}
1095 			bufferevent_write(s->client_bufev, linebuf, linelen);
1096 		}
1097 
1098 		if (n == -1) {
1099 			logmsg(LOG_ERR, "#%d server reply too long or not"
1100 			    " clean", s->id);
1101 			end_session(s);
1102 			return;
1103 		}
1104 	} while (read == buf_avail);
1105 }
1106 
1107 const char *
sock_ntop(struct sockaddr * sa)1108 sock_ntop(struct sockaddr *sa)
1109 {
1110 	static int n = 0;
1111 
1112 	/* Cycle to next buffer. */
1113 	n = (n + 1) % NTOP_BUFS;
1114 	ntop_buf[n][0] = '\0';
1115 
1116 	if (sa->sa_family == AF_INET) {
1117 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1118 
1119 		return (inet_ntop(AF_INET, &sin->sin_addr, ntop_buf[n],
1120 		    sizeof ntop_buf[0]));
1121 	}
1122 
1123 	if (sa->sa_family == AF_INET6) {
1124 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
1125 
1126 		return (inet_ntop(AF_INET6, &sin6->sin6_addr, ntop_buf[n],
1127 		    sizeof ntop_buf[0]));
1128 	}
1129 
1130 	return (NULL);
1131 }
1132 
1133 void
usage(void)1134 usage(void)
1135 {
1136 	fprintf(stderr, "usage: %s [-6Adrv] [-a sourceaddr] [-b address]"
1137 	    " [-D level] [-m maxsessions]\n                 [-P port]"
1138 	    " [-p port] [-q queue] [-R address] [-T tag]\n"
1139             "                 [-t timeout]\n", __progname);
1140 	exit(1);
1141 }
1142 
1143 int
rdaemon(int devnull)1144 rdaemon(int devnull)
1145 {
1146 	if (devnull == -1) {
1147 		errno = EBADF;
1148 		return (-1);
1149 	}
1150 	if (fcntl(devnull, F_GETFL) == -1)
1151 		return (-1);
1152 
1153 	switch (fork()) {
1154 	case -1:
1155 		return (-1);
1156 	case 0:
1157 		break;
1158 	default:
1159 		_exit(0);
1160 	}
1161 
1162 	if (setsid() == -1)
1163 		return (-1);
1164 
1165 	(void)dup2(devnull, STDIN_FILENO);
1166 	(void)dup2(devnull, STDOUT_FILENO);
1167 	(void)dup2(devnull, STDERR_FILENO);
1168 	if (devnull > 2)
1169 		(void)close(devnull);
1170 
1171 	return (0);
1172 }
1173