If a connected host disappears without our knowledge, as can happen over
wireless or a hibernating machine, we continue to hold the port open waiting
for messages. Because we never try to send anything down this now-broken
pipe, the connection will sit idle taking up a slot in our allowed incoming
connections list.

If enough of these happen, an unintended Denial of Service takes place,
where all connection slots are filled with now-broken, never ending
connections. Setting the TCP keepalive option at least allows these to time
out after the default two hours, which is sufficient in the non-malicious
case.

Signed-off-by: Dan McGee <d...@archlinux.org>
---
 src/server_socket.c |    8 ++++++--
 src/socket_util.c   |   15 +++++++++++++++
 src/socket_util.h   |    3 +++
 3 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/src/server_socket.c b/src/server_socket.c
index 82ad81f..fc8dbd1 100644
--- a/src/server_socket.c
+++ b/src/server_socket.c
@@ -160,12 +160,16 @@ server_socket_in_event(G_GNUC_UNUSED GIOChannel *source,
        size_t address_length = sizeof(address);
        int fd = accept_cloexec_nonblock(s->fd, (struct sockaddr*)&address,
                                         &address_length);
-       if (fd >= 0)
+       if (fd >= 0) {
+               if (socket_keepalive(fd))
+                       g_warning("Could not set TCP keepalive option: %s",
+                                 g_strerror(errno));
                s->parent->callback(fd, (const struct sockaddr*)&address,
                                    address_length, get_remote_uid(fd),
                                    s->parent->callback_ctx);
-       else
+       } else {
                g_warning("accept() failed: %s", g_strerror(errno));
+       }
 
        return true;
 }
diff --git a/src/socket_util.c b/src/socket_util.c
index a89a67e..aa0a44e 100644
--- a/src/socket_util.c
+++ b/src/socket_util.c
@@ -148,3 +148,18 @@ socket_bind_listen(int domain, int type, int protocol,
 
        return fd;
 }
+
+int
+socket_keepalive(int fd)
+{
+       const int reuse = 1;
+
+#ifdef WIN32
+       const char *optval = (const char *)&reuse;
+#else
+       const void *optval = &reuse;
+#endif
+
+       return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
+                       optval, sizeof(reuse));
+}
diff --git a/src/socket_util.h b/src/socket_util.h
index 3ebf408..f27751a 100644
--- a/src/socket_util.h
+++ b/src/socket_util.h
@@ -63,4 +63,7 @@ socket_bind_listen(int domain, int type, int protocol,
                   int backlog,
                   GError **error);
 
+int
+socket_keepalive(int fd);
+
 #endif
-- 
1.7.6.1


------------------------------------------------------------------------------
BlackBerry&reg; DevCon Americas, Oct. 18-20, San Francisco, CA
Learn about the latest advances in developing for the 
BlackBerry&reg; mobile platform with sessions, labs & more.
See new tools and technologies. Register for BlackBerry&reg; DevCon today!
http://p.sf.net/sfu/rim-devcon-copy1 
_______________________________________________
Musicpd-dev-team mailing list
Musicpd-dev-team@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team

Reply via email to