--- Quoting Camiel Dobbelaar on 2008/04/02 at 17:32 +0200:

> Michael Hoffrath wrote:
> > Same problem here Running OpenBSD 4.2 (GENERIC) #375 i386.
> > 
> > It seems not only being a problem of Microsoft, I've found that problem also
> > on  VSFTPd (centos) and Filezilla (Windows 2003 Server). 
> > 
> > Both are sending "221 Goodbye" but ftp-proxy seems to swallow that from time
> > to time. 
> 
> It sounds like a race condition, where the server FIN reaches the proxy
> before the final data is sent out to the client.  I'd have to dig into
> it a bit more.

That's exactly what I saw when I broke out the sniffer to troubleshoot
this.

> Does it cause a real problem?  (in other words: how urgent is the fix?)

Unfortunately there seems to be a lot of shitty software out there that
waits explicitly for the 221 response even though the TCP socket that
that response is supposed to come in on has been closed.

This is the patch that I've been running in production for some weeks.
The firewall where I'm running this proxies outgoing ftp connections and
also sits in front of an FTP server so I have two instances of ftp-proxy
running. The patch fixes the 221 issue however I recently started
getting reports of users being unable to ftp outbound. Seems the patch
is causing ftp-proxy to crash at random (but only the instance that
proxies the outgoing connections). I haven't had time to debug that yet.





.joel



Index: ftp-proxy.c
===================================================================
RCS file: /cvs/src/usr.sbin/ftp-proxy/ftp-proxy.c,v
retrieving revision 1.13
diff -p -u -r1.13 ftp-proxy.c
--- ftp-proxy.c 30 Dec 2006 13:24:00 -0000      1.13
+++ ftp-proxy.c 8 Mar 2008 00:56:38 -0000
@@ -79,6 +79,8 @@ struct session {
        int                      cmd;
        u_int16_t                port;
        u_int16_t                proxy_port;
+       u_int8_t                 client_closed;
+       u_int8_t                 server_closed;
        LIST_ENTRY(session)      entry;
 };
 
@@ -91,6 +93,8 @@ int   client_parse_cmd(struct session *s);
 void   client_read(struct bufferevent *, void *);
 int    drop_privs(void);
 void   end_session(struct session *);
+void   end_session_client(struct session *);
+void   end_session_server(struct session *);
 int    exit_daemon(void);
 int    getline(char *, size_t *);
 void   handle_connection(const int, short, void *);
@@ -134,7 +138,7 @@ client_error(struct bufferevent *bufev, 
        else
                logmsg(LOG_ERR, "#%d abnormal client error: %d", s->id, what);
 
-       end_session(s);
+       end_session_client(s);
 }
 
 int
@@ -270,15 +274,18 @@ end_session(struct session *s)
 
        logmsg(LOG_INFO, "#%d ending session", s->id);
 
-       if (s->client_fd != -1)
-               close(s->client_fd);
-       if (s->server_fd != -1)
-               close(s->server_fd);
-
-       if (s->client_bufev)
-               bufferevent_free(s->client_bufev);
-       if (s->server_bufev)
-               bufferevent_free(s->server_bufev);
+       if (!s->client_closed) {
+               if (s->client_fd != -1)
+                       close(s->client_fd);
+               if (s->client_bufev)
+                       bufferevent_free(s->client_bufev);
+       }
+       if (!s->server_closed) {
+               if (s->server_fd != -1)
+                       close(s->server_fd);
+               if (s->server_bufev)
+                       bufferevent_free(s->server_bufev);
+       }
 
        /* Remove rulesets by commiting empty ones. */
        err = 0;
@@ -297,6 +304,42 @@ end_session(struct session *s)
        session_count--;
 }
 
+void
+end_session_client(struct session *s)
+{
+       logmsg(LOG_INFO, "#%d ending client session", s->id);
+
+       if (s->client_fd != -1)
+               close(s->client_fd);
+
+       if (s->client_bufev)
+               bufferevent_free(s->client_bufev);
+
+       s->client_closed++;
+
+       /* server connection is already closed, shut everything down */
+       if (s->server_closed)
+               end_session(s);
+}
+
+void
+end_session_server(struct session *s)
+{
+       logmsg(LOG_INFO, "#%d ending server session", s->id);
+
+       if (s->server_fd != -1)
+               close(s->server_fd);
+
+       if (s->server_bufev)
+               bufferevent_free(s->server_bufev);
+
+       s->server_closed++;
+
+       /* client connection is already closed, shut everything down */
+       if (s->client_closed)
+               end_session(s);
+}
+
 int
 exit_daemon(void)
 {
@@ -882,7 +925,7 @@ server_error(struct bufferevent *bufev, 
        else
                logmsg(LOG_ERR, "#%d abnormal server error: %d", s->id, what);
 
-       end_session(s);
+       end_session_server(s);
 }
 
 int

Reply via email to