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