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