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