Unix Technical Forum

Re: ftp-proxy diff, please test

This is a discussion on Re: ftp-proxy diff, please test within the mailing.openbsd.tech forums, part of the OpenBSD category; --> Anyone testing this one? I'd like at least two reports. Thanks. On Fri, 8 Dec 2006, Camiel Dobbelaar wrote: ...


Go Back   Unix Technical Forum > Unix Operating Systems > OpenBSD > mailing.openbsd.tech

FAQ Members List Calendar Search Today's Posts Mark Forums Read
  #1 (permalink)  
Old 02-18-2008, 09:04 AM
Camiel Dobbelaar
 
Posts: n/a
Default Re: ftp-proxy diff, please test

Anyone testing this one? I'd like at least two reports.

Thanks.


On Fri, 8 Dec 2006, Camiel Dobbelaar wrote:

> This diff makes ftp-proxy use the readline function from libevent, so the
> custom getline() function and the two static buffers per session can all
> be done away with.
>
> Keep an eye on the ftp-proxy process to see if it does not grow slowly
> (libevent readline is malloc/free based).
>
> Thanks.
>
>
> Index: ftp-proxy.c
> ================================================== =================
> RCS file: /cvs/src/usr.sbin/ftp-proxy/ftp-proxy.c,v
> retrieving revision 1.10
> diff -u -p -r1.10 ftp-proxy.c
> --- ftp-proxy.c 15 Oct 2006 18:23:44 -0000 1.10
> +++ ftp-proxy.c 7 Dec 2006 12:16:41 -0000
> @@ -51,6 +51,7 @@
> #define NTOP_BUFS 3
> #define TCP_BACKLOG 10
>
> +#define ANON_ONLY_MSG "500 Only anonymous FTP allowed"
> #define CHROOT_DIR "/var/empty"
> #define NOPRIV_USER "proxy"
>
> @@ -72,10 +73,6 @@ struct session {
> struct bufferevent *server_bufev;
> int client_fd;
> int server_fd;
> - char cbuf[MAX_LINE];
> - size_t cbuf_valid;
> - char sbuf[MAX_LINE];
> - size_t sbuf_valid;
> int cmd;
> u_int16_t port;
> u_int16_t proxy_port;
> @@ -85,32 +82,30 @@ struct session {
> LIST_HEAD(, session) sessions = LIST_HEAD_INITIALIZER(sessions);
>
> void client_error(struct bufferevent *, short, void *);
> -int client_parse(struct session *s);
> -int client_parse_anon(struct session *s);
> -int client_parse_cmd(struct session *s);
> +int client_parse(struct session *s, char **);
> +int client_parse_anon(struct session *s, char **);
> +int client_parse_cmd(struct session *s, char **);
> void client_read(struct bufferevent *, void *);
> +int client_send(struct session *, char *);
> void client_write(struct bufferevent *, void *);
> int drop_privs(void);
> void end_session(struct session *);
> int exit_daemon(void);
> -int getline(char *, size_t *);
> void handle_connection(const int, short, void *);
> void handle_signal(int, short, void *);
> struct session * init_session(void);
> void logmsg(int, const char *, ...);
> -u_int16_t parse_port(int);
> +u_int16_t parse_port(int, char *);
> u_int16_t pick_proxy_port(void);
> -void proxy_reply(int, struct sockaddr *, u_int16_t);
> +char *proxy_reply(int, struct sockaddr *, u_int16_t);
> void server_error(struct bufferevent *, short, void *);
> -int server_parse(struct session *s);
> +int server_parse(struct session *s, char **);
> void server_read(struct bufferevent *, void *);
> +int server_send(struct session *, char *);
> void server_write(struct bufferevent *, void *);
> const char *sock_ntop(struct sockaddr *);
> void usage(void);
>
> -char linebuf[MAX_LINE + 1];
> -size_t linelen;
> -
> char ntop_buf[NTOP_BUFS][INET6_ADDRSTRLEN];
>
> struct sockaddr_storage fixed_server_ss, fixed_proxy_ss;
> @@ -140,57 +135,48 @@ client_error(struct bufferevent *bufev,
> }
>
> int
> -client_parse(struct session *s)
> +client_parse(struct session *s, char **line)
> {
> /* Reset any previous command. */
> s->cmd = CMD_NONE;
> s->port = 0;
>
> - /* Commands we are looking for are at least 4 chars long. */
> - if (linelen < 4)
> - return (1);
> -
> - if (linebuf[0] == 'P' || linebuf[0] == 'p' ||
> - linebuf[0] == 'E' || linebuf[0] == 'e')
> - return (client_parse_cmd(s));
> + if (*line[0] == 'P' || *line[0] == 'p' ||
> + *line[0] == 'E' || *line[0] == 'e')
> + return (client_parse_cmd(s, line));
>
> - if (anonymous_only && (linebuf[0] == 'U' || linebuf[0] == 'u'))
> - return (client_parse_anon(s));
> + if (anonymous_only && (*line[0] == 'U' || *line[0] == 'u'))
> + return (client_parse_anon(s, line));
>
> return (1);
> }
>
> int
> -client_parse_anon(struct session *s)
> +client_parse_anon(struct session *s, char **line)
> {
> - if (strcasecmp("USER ftp\r\n", linebuf) != 0 &&
> - strcasecmp("USER anonymous\r\n", linebuf) != 0) {
> - snprintf(linebuf, sizeof linebuf,
> - "500 Only anonymous FTP allowed\r\n");
> - logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, linebuf);
> + if (strcasecmp("USER ftp", *line) != 0 &&
> + strcasecmp("USER anonymous", *line) != 0) {
> + /* Clear line so it's not sent to the server. */
> + free(*line);
> + *line = NULL;
>
> /* Talk back to the client ourself. */
> - linelen = strlen(linebuf);
> - bufferevent_write(s->client_bufev, linebuf, linelen);
> -
> - /* Clear buffer so it's not sent to the server. */
> - linebuf[0] = '\0';
> - linelen = 0;
> + logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, ANON_ONLY_MSG);
> + return (client_send(s, ANON_ONLY_MSG "\r\n"));
> }
> -
> return (1);
> }
>
> int
> -client_parse_cmd(struct session *s)
> +client_parse_cmd(struct session *s, char **line)
> {
> - if (strncasecmp("PASV", linebuf, 4) == 0)
> + if (strncasecmp("PASV", *line, 4) == 0)
> s->cmd = CMD_PASV;
> - else if (strncasecmp("PORT ", linebuf, 5) == 0)
> + else if (strncasecmp("PORT ", *line, 5) == 0)
> s->cmd = CMD_PORT;
> - else if (strncasecmp("EPSV", linebuf, 4) == 0)
> + else if (strncasecmp("EPSV", *line, 4) == 0)
> s->cmd = CMD_EPSV;
> - else if (strncasecmp("EPRT ", linebuf, 5) == 0)
> + else if (strncasecmp("EPRT ", *line, 5) == 0)
> s->cmd = CMD_EPRT;
> else
> return (1);
> @@ -201,15 +187,22 @@ client_parse_cmd(struct session *s)
> }
>
> if (s->cmd == CMD_PORT || s->cmd == CMD_EPRT) {
> - s->port = parse_port(s->cmd);
> + s->port = parse_port(s->cmd, *line);
> if (s->port < MIN_PORT) {
> - logmsg(LOG_CRIT, "#%d bad port in '%s'", s->id,
> - linebuf);
> + logmsg(LOG_CRIT, "#%d bad port in '%s'", s->id, *line);
> return (0);
> }
> s->proxy_port = pick_proxy_port();
> - proxy_reply(s->cmd, sstosa(&s->proxy_ss), s->proxy_port);
> - logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, linebuf);
> +
> + /* Rewrite the client command. */
> + free(*line);
> + *line = proxy_reply(s->cmd, sstosa(&s->proxy_ss),
> + s->proxy_port);
> + if (*line == NULL) {
> + logmsg(LOG_ERR, "#%d client proxy_reply failed", s->id);
> + return (0);
> + }
> + logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, *line);
> }
>
> return (1);
> @@ -219,31 +212,45 @@ void
> client_read(struct bufferevent *bufev, void *arg)
> {
> struct session *s = arg;
> - size_t buf_avail, read;
> - int n;
> + size_t linelen;
> + char *line;
>
> - do {
> - buf_avail = sizeof s->cbuf - s->cbuf_valid;
> - read = bufferevent_read(bufev, s->cbuf + s->cbuf_valid,
> - buf_avail);
> - s->cbuf_valid += read;
> -
> - while ((n = getline(s->cbuf, &s->cbuf_valid)) > 0) {
> - logmsg(LOG_DEBUG, "#%d client: %s", s->id, linebuf);
> - if (!client_parse(s)) {
> - end_session(s);
> - return;
> - }
> - bufferevent_write(s->server_bufev, linebuf, linelen);
> + while ((line = evbuffer_readline(bufev->input))) {
> + linelen = strlen(line);
> + if (linelen > MAX_LINE) {
> + logmsg(LOG_ERR, "#%d client command too long", s->id);
> + goto fail;
> }
> + logmsg(LOG_DEBUG, "#%d client: %s", s->id, line);
>
> - if (n == -1) {
> - logmsg(LOG_ERR, "#%d client command too long or not"
> - " clean", s->id);
> - end_session(s);
> - return;
> - }
> - } while (read == buf_avail);
> + if (linelen > 0 && !client_parse(s, &line))
> + goto fail;
> +
> + /* Send line to server; client_parse() may have changed it. */
> + if (!server_send(s, line))
> + goto fail;
> +
> + free(line);
> + }
> + return;
> + fail:
> + free(line);
> + end_session(s);
> +}
> +
> +int
> +client_send(struct session *s, char *line)
> +{
> + if (evbuffer_add_printf(s->client_bufev->output, "%s\r\n", line) < 0) {
> + logmsg(LOG_ERR, "#%d client_send printf failed", s->id);
> + return (0);
> + }
> + if (event_add(&s->client_bufev->ev_write, NULL) < 0) {
> + logmsg(LOG_ERR, " #%d client_send event_add failed: %s",
> + s->id, strerror(errno));
> + return (0);
> + }
> + return (1);
> }
>
> void
> @@ -324,43 +331,6 @@ exit_daemon(void)
> return (-1);
> }
>
> -int
> -getline(char *buf, size_t *valid)
> -{
> - size_t i;
> -
> - if (*valid > MAX_LINE)
> - return (-1);
> -
> - /* Copy to linebuf while searching for a newline. */
> - for (i = 0; i < *valid; i++) {
> - linebuf[i] = buf[i];
> - if (buf[i] == '\0')
> - return (-1);
> - if (buf[i] == '\n')
> - break;
> - }
> -
> - if (i == *valid) {
> - /* No newline found. */
> - linebuf[0] = '\0';
> - linelen = 0;
> - if (i < MAX_LINE)
> - return (0);
> - return (-1);
> - }
> -
> - linelen = i + 1;
> - linebuf[linelen] = '\0';
> - *valid -= linelen;
> -
> - /* Move leftovers to the start. */
> - if (*valid != 0)
> - bcopy(buf + linelen, buf, *valid);
> -
> - return ((int)linelen);
> -}
> -
> void
> handle_connection(const int listen_fd, short event, void *ev)
> {
> @@ -533,10 +503,6 @@ init_session(void)
> s->id = id_count++;
> s->client_fd = -1;
> s->server_fd = -1;
> - s->cbuf[0] = '\0';
> - s->cbuf_valid = 0;
> - s->sbuf[0] = '\0';
> - s->sbuf_valid = 0;
> s->client_bufev = NULL;
> s->server_bufev = NULL;
> s->cmd = CMD_NONE;
> @@ -767,17 +733,17 @@ main(int argc, char *argv[])
> }
>
> u_int16_t
> -parse_port(int mode)
> +parse_port(int mode, char *line)
> {
> unsigned int port, v[6];
> int n;
> char *p;
>
> /* Find the last space or left-parenthesis. */
> - for (p = linebuf + linelen; p > linebuf; p--)
> + for (p = line + strlen(line); p > line; p--)
> if (*p == ' ' || *p == '(')
> break;
> - if (p == linebuf)
> + if (p == line)
> return (0);
>
> switch (mode) {
> @@ -825,50 +791,46 @@ pick_proxy_port(void)
> (IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO)));
> }
>
> -void
> +char *
> proxy_reply(int cmd, struct sockaddr *sa, u_int16_t port)
> {
> int i, r;
> + char *reply;
>
> switch (cmd) {
> case CMD_PORT:
> - r = snprintf(linebuf, sizeof linebuf,
> - "PORT %s,%u,%u\r\n", sock_ntop(sa), port / 256,
> - port % 256);
> + r = asprintf(&reply, "PORT %s,%u,%u", sock_ntop(sa),
> + port / 256, port % 256);
> break;
> case CMD_PASV:
> - r = snprintf(linebuf, sizeof linebuf,
> - "227 Entering Passive Mode (%s,%u,%u)\r\n", sock_ntop(sa),
> - port / 256, port % 256);
> + r = asprintf(&reply, "227 Entering Passive Mode (%s,%u,%u)",
> + sock_ntop(sa), port / 256, port % 256);
> break;
> case CMD_EPRT:
> if (sa->sa_family == AF_INET)
> - r = snprintf(linebuf, sizeof linebuf,
> - "EPRT |1|%s|%u|\r\n", sock_ntop(sa), port);
> + r = asprintf(&reply, "EPRT |1|%s|%u|", sock_ntop(sa),
> + port);
> else if (sa->sa_family == AF_INET6)
> - r = snprintf(linebuf, sizeof linebuf,
> - "EPRT |2|%s|%u|\r\n", sock_ntop(sa), port);
> + r = asprintf(&reply, "EPRT |2|%s|%u|", sock_ntop(sa),
> + port);
> break;
> case CMD_EPSV:
> - r = snprintf(linebuf, sizeof linebuf,
> - "229 Entering Extended Passive Mode (|||%u|)\r\n", port);
> + r = asprintf(&reply,
> + "229 Entering Extended Passive Mode (|||%u|)", port);
> break;
> }
>
> - if (r < 0 || r >= sizeof linebuf) {
> - logmsg(LOG_ERR, "proxy_reply failed: %d", r);
> - linebuf[0] = '\0';
> - linelen = 0;
> - return;
> - }
> - linelen = (size_t)r;
> + if (r < 0)
> + return (NULL);
>
> if (cmd == CMD_PORT || cmd == CMD_PASV) {
> /* Replace dots in IP address with commas. */
> - for (i = 0; i < linelen; i++)
> - if (linebuf[i] == '.')
> - linebuf[i] = ',';
> + for (i = 0; i < r; i++)
> + if (reply[i] == '.')
> + reply[i] = ',';
> }
> +
> + return (reply);
> }
>
> void
> @@ -891,12 +853,12 @@ server_error(struct bufferevent *bufev,
> }
>
> int
> -server_parse(struct session *s)
> +server_parse(struct session *s, char **line)
> {
> struct sockaddr *client_sa, *orig_sa, *proxy_sa, *server_sa;
> int prepared = 0;
>
> - if (s->cmd == CMD_NONE || linelen < 4 || linebuf[0] != '2')
> + if (s->cmd == CMD_NONE || *line[0] != '2')
> goto out;
>
> /*
> @@ -923,25 +885,30 @@ server_parse(struct session *s)
> orig_sa = sstosa(&s->server_ss);
>
> /* Passive modes. */
> - if ((s->cmd == CMD_PASV && strncmp("227 ", linebuf, 4) == 0) ||
> - (s->cmd == CMD_EPSV && strncmp("229 ", linebuf, 4) == 0)) {
> - s->port = parse_port(s->cmd);
> + if ((s->cmd == CMD_PASV && strncmp("227 ", *line, 4) == 0) ||
> + (s->cmd == CMD_EPSV && strncmp("229 ", *line, 4) == 0)) {
> + s->port = parse_port(s->cmd, *line);
> if (s->port < MIN_PORT) {
> - logmsg(LOG_CRIT, "#%d bad port in '%s'", s->id,
> - linebuf);
> + logmsg(LOG_CRIT, "#%d bad port in '%s'", s->id, *line);
> return (0);
> }
> s->proxy_port = pick_proxy_port();
> logmsg(LOG_INFO, "#%d passive: client to server port %d"
> " via port %d", s->id, s->port, s->proxy_port);
>
> + /* Rewrite the server reply. */
> + free(*line);
> + *line = proxy_reply(s->cmd, orig_sa, s->proxy_port);
> + if (*line == NULL) {
> + logmsg(LOG_ERR, "#%d server proxy_reply failed", s->id);
> + return (0);
> + }
> + logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, *line);
> +
> if (prepare_commit(s->id) == -1)
> goto fail;
> prepared = 1;
>
> - proxy_reply(s->cmd, orig_sa, s->proxy_port);
> - logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, linebuf);
> -
> /* rdr from $client to $orig_server port $proxy_port -> $server
> port $port */
> if (add_rdr(s->id, client_sa, orig_sa, s->proxy_port,
> @@ -966,7 +933,7 @@ server_parse(struct session *s)
>
> /* Active modes. */
> if ((s->cmd == CMD_PORT || s->cmd == CMD_EPRT) &&
> - strncmp("200 ", linebuf, 4) == 0) {
> + strncmp("200 ", *line, 4) == 0) {
> logmsg(LOG_INFO, "#%d active: server to client port %d"
> " via port %d", s->id, s->port, s->proxy_port);
>
> @@ -1033,33 +1000,47 @@ void
> server_read(struct bufferevent *bufev, void *arg)
> {
> struct session *s = arg;
> - size_t buf_avail, read;
> - int n;
> + size_t linelen;
> + char *line;
>
> bufferevent_settimeout(bufev, timeout, 0);
>
> - do {
> - buf_avail = sizeof s->sbuf - s->sbuf_valid;
> - read = bufferevent_read(bufev, s->sbuf + s->sbuf_valid,
> - buf_avail);
> - s->sbuf_valid += read;
> -
> - while ((n = getline(s->sbuf, &s->sbuf_valid)) > 0) {
> - logmsg(LOG_DEBUG, "#%d server: %s", s->id, linebuf);
> - if (!server_parse(s)) {
> - end_session(s);
> - return;
> - }
> - bufferevent_write(s->client_bufev, linebuf, linelen);
> + while ((line = evbuffer_readline(bufev->input))) {
> + linelen = strlen(line);
> + if (linelen > MAX_LINE) {
> + logmsg(LOG_ERR, "#%d server reply too long", s->id);
> + goto fail;
> }
> + logmsg(LOG_DEBUG, "#%d server: %s", s->id, line);
>
> - if (n == -1) {
> - logmsg(LOG_ERR, "#%d server reply too long or not"
> - " clean", s->id);
> - end_session(s);
> - return;
> - }
> - } while (read == buf_avail);
> + if (linelen > 0 && !server_parse(s, &line))
> + goto fail;
> +
> + /* Send line to client; server_parse() may have changed it. */
> + if (!client_send(s, line))
> + goto fail;
> +
> + free(line);
> + }
> + return;
> + fail:
> + free(line);
> + end_session(s);
> +}
> +
> +int
> +server_send(struct session *s, char *line)
> +{
> + if (evbuffer_add_printf(s->server_bufev->output, "%s\r\n", line) < 0) {
> + logmsg(LOG_ERR, "#%d server_send printf failed", s->id);
> + return (0);
> + }
> + if (event_add(&s->server_bufev->ev_write, NULL) < 0) {
> + logmsg(LOG_ERR, " #%d server_send event_add failed: %s",
> + s->id, strerror(errno));
> + return (0);
> + }
> + return (1);
> }
>
> void


Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Forum Jump


All times are GMT. The time now is 08:53 AM.


Powered by vBulletin® Version 3.6.5
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
SEO by vBSEO 3.2.0
www.UnixAdminTalk.com