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