Skip to content
Permalink
Browse files
Enable UDP by default, clean up server socket code (Brian Aker)
git-svn-id: http://code.sixapart.com/svn/memcached/trunk/server@726 b0b603af-a30f-0410-a34e-baf09ae79d0b
  • Loading branch information
BrianAker committed Feb 27, 2008
1 parent a6b35b4 commit 2439472aae5960b9b2f8ef93f3f62047a28700f2
Showing with 74 additions and 126 deletions.
  1. +74 −126 memcached.c
@@ -64,7 +64,7 @@ std *
*/
static void drive_machine(conn *c);
static int new_socket(struct addrinfo *ai);
static int *server_socket(const int port, const bool is_udp, int *count);
static int server_socket(const int port, const bool is_udp);
static int try_read_command(conn *c);
static int try_read_network(conn *c);
static int try_read_udp(conn *c);
@@ -2391,10 +2391,8 @@ static void maximize_sndbuf(const int sfd) {
}


static int *server_socket(const int port, const bool is_udp, int *count) {
static int server_socket(const int port, const bool is_udp) {
int sfd;
int *sfd_list;
int *sfd_ptr;
struct linger ling = {0, 0};
struct addrinfo *ai;
struct addrinfo *next;
@@ -2430,23 +2428,15 @@ static int *server_socket(const int port, const bool is_udp, int *count) {
else
perror("getaddrinfo()");

return NULL;
return 1;
}

for (*count= 1, next= ai; next->ai_next; next= next->ai_next, (*count)++);

sfd_list= (int *)calloc(*count, sizeof(int));
if (sfd_list == NULL) {
fprintf(stderr, "calloc()\n");
return NULL;
}
memset(sfd_list, -1, sizeof(int) * (*count));

for (sfd_ptr= sfd_list, next= ai; next; next= next->ai_next, sfd_ptr++) {
conn *conn_ptr = NULL;
for (next= ai; next; next= next->ai_next) {
conn *listen_conn_add;
if ((sfd = new_socket(next)) == -1) {
free(sfd_list);
freeaddrinfo(ai);
return NULL;
return 1;
}

setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
@@ -2461,47 +2451,48 @@ static int *server_socket(const int port, const bool is_udp, int *count) {
if (bind(sfd, next->ai_addr, next->ai_addrlen) == -1) {
if (errno != EADDRINUSE) {
perror("bind()");
/* If we are not at the first element, loop back and close all sockets */
if (sfd_ptr != sfd_list) {
do {
--sfd_ptr;
close(*sfd_ptr);
} while (sfd_ptr != sfd_list);
}
close(sfd);
freeaddrinfo(ai);
free(sfd_list);
return NULL;
return 1;
}
close(sfd);
*sfd_ptr= -1;
} else {
success++;
*sfd_ptr= sfd;
if (!is_udp && listen(sfd, 1024) == -1) {
perror("listen()");
if (sfd_ptr != sfd_list) {
do {
--sfd_ptr;
close(*sfd_ptr);
} while (sfd_ptr != sfd_list);
}
close(sfd);
freeaddrinfo(ai);
free(sfd_list);
return NULL;
return 1;
}
}
}

freeaddrinfo(ai);
if (is_udp)
{
int c;

if (success == 0) {
free(sfd_list);
return NULL;
for (c = 0; c < settings.num_threads; c++) {
/* this is guaranteed to hit all threads because we round-robin */
dispatch_conn_new(sfd, conn_read, EV_READ | EV_PERSIST,
UDP_READ_BUFFER_SIZE, 1);
}
} else {
if (!(listen_conn_add = conn_new(sfd, conn_listening,
EV_READ | EV_PERSIST, 1, false, main_base))) {
fprintf(stderr, "failed to create listening connection\n");
exit(EXIT_FAILURE);
}

if (listen_conn == NULL) {
conn_ptr = listen_conn = listen_conn_add;
} else {
conn_ptr->next= listen_conn_add;
}
}
}

return sfd_list;
freeaddrinfo(ai);

return 0;
}

static int new_socket_unix(void) {
@@ -2522,33 +2513,21 @@ static int new_socket_unix(void) {
return sfd;
}

static int *server_socket_unix(const char *path, int access_mask) {
static int server_socket_unix(const char *path, int access_mask) {
int sfd;
int *sfd_list;
struct linger ling = {0, 0};
struct sockaddr_un addr;
struct stat tstat;
int flags =1;
int old_umask;

if (!path) {
return NULL;
return 1;
}

if ((sfd = new_socket_unix()) == -1) {
return NULL;
}

/*
When UNIX domain sockets get refactored, this will go away.
For now we know there is just one socket.
*/
sfd_list= (int *)calloc(1, sizeof(int));
if (sfd_list == NULL) {
fprintf(stderr, "calloc()\n");
return NULL;
return 1;
}
memset(sfd_list, -1, sizeof(int) * 1);

/*
* Clean up a previous socket file if we left it around
@@ -2574,21 +2553,22 @@ static int *server_socket_unix(const char *path, int access_mask) {
if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("bind()");
close(sfd);
free(sfd_list);
umask(old_umask);
return NULL;
return 1;
}
umask(old_umask);
if (listen(sfd, 1024) == -1) {
perror("listen()");
close(sfd);
free(sfd_list);
return NULL;
return 1;
}
if (!(listen_conn = conn_new(sfd, conn_listening,
EV_READ | EV_PERSIST, 1, false, main_base))) {
fprintf(stderr, "failed to create listening connection\n");
exit(EXIT_FAILURE);
}

*sfd_list= sfd;

return sfd_list;
return 0;
}

/*
@@ -2869,7 +2849,6 @@ int main (int argc, char **argv) {
struct rlimit rlim;
/* listening socket */
static int *l_socket = NULL;
static int l_socket_count = 0;

/* udp socket */
static int *u_socket = NULL;
@@ -3028,31 +3007,6 @@ int main (int argc, char **argv) {
}
}

/*
* initialization order: first create the listening sockets
* (may need root on low ports), then drop root if needed,
* then daemonise if needed, then init libevent (in some cases
* descriptors created by libevent wouldn't survive forking).
*/

/* create the listening socket and bind it */
if (settings.socketpath == NULL) {
l_socket = server_socket(settings.port, 0, &l_socket_count);
if (l_socket == NULL) {
fprintf(stderr, "failed to listen\n");
exit(EXIT_FAILURE);
}
}

if (settings.udpport > 0 && settings.socketpath == NULL) {
/* create the UDP listening socket and bind it */
u_socket = server_socket(settings.udpport, 1, &u_socket_count);
if (u_socket == NULL) {
fprintf(stderr, "failed to listen on UDP port %d\n", settings.udpport);
exit(EXIT_FAILURE);
}
}

/* lock paged memory if needed */
if (lock_memory) {
#ifdef HAVE_MLOCKALL
@@ -3082,17 +3036,6 @@ int main (int argc, char **argv) {
}
}

/* create unix mode sockets after dropping privileges */
if (settings.socketpath != NULL) {
l_socket = server_socket_unix(settings.socketpath,settings.access);
if (l_socket == NULL) {
fprintf(stderr, "failed to listen\n");
exit(EXIT_FAILURE);
}
/* We only support one of these, so whe know the count */
l_socket_count = 1;
}

/* daemonize if requested */
/* if we want to ensure our ability to dump core, don't chdir to / */
if (daemonize) {
@@ -3138,25 +3081,6 @@ int main (int argc, char **argv) {
perror("failed to ignore SIGPIPE; sigaction");
exit(EXIT_FAILURE);
}
/* create the initial listening connection */
int *l_socket_ptr;
conn *next = NULL;
for (l_socket_ptr= l_socket, x = 0; x < l_socket_count; l_socket_ptr++, x++) {
conn *listen_conn_add;
if (*l_socket_ptr > -1 ) {
if (!(listen_conn_add = conn_new(*l_socket_ptr, conn_listening,
EV_READ | EV_PERSIST, 1, false, main_base))) {
fprintf(stderr, "failed to create listening connection\n");
exit(EXIT_FAILURE);
}

if (listen_conn == NULL) {
next = listen_conn = listen_conn_add;
} else {
next->next= listen_conn_add;
}
}
}
/* start up worker threads if MT mode */
thread_init(settings.num_threads, main_base);
/* save the PID in if we're a daemon, do this after thread_init due to
@@ -3173,14 +3097,38 @@ int main (int argc, char **argv) {
exit(EXIT_FAILURE);
}
delete_handler(0, 0, 0); /* sets up the event */
/* create the initial listening udp connection, monitored on all threads */
if (u_socket) {
for (c = 0; c < settings.num_threads; c++) {
/* this is guaranteed to hit all threads because we round-robin */
dispatch_conn_new(*u_socket, conn_read, EV_READ | EV_PERSIST,
UDP_READ_BUFFER_SIZE, 1);

/* create unix mode sockets after dropping privileges */
if (settings.socketpath != NULL) {
if (server_socket_unix(settings.socketpath,settings.access)) {
fprintf(stderr, "failed to listen\n");
exit(EXIT_FAILURE);
}
}

/* create the listening socket, bind it, and init */
if (settings.socketpath == NULL) {
int udp_port;

if (server_socket(settings.port, 0)) {
fprintf(stderr, "failed to listen\n");
exit(EXIT_FAILURE);
}
/*
* initialization order: first create the listening sockets
* (may need root on low ports), then drop root if needed,
* then daemonise if needed, then init libevent (in some cases
* descriptors created by libevent wouldn't survive forking).
*/
udp_port = settings.udpport ? settings.udpport : settings.port;

/* create the UDP listening socket and bind it */
if (server_socket(udp_port, 1)) {
fprintf(stderr, "failed to listen on UDP port %d\n", settings.udpport);
exit(EXIT_FAILURE);
}
}

/* enter the event loop */
event_base_loop(main_base, 0);
/* remove the PID file if we're a daemon */

3 comments on commit 2439472

@janreges

This comment has been minimized.

Copy link

@janreges janreges replied Feb 27, 2018

Hi,

this commit was starter of current biggest UDP amplification attack with impact bigger than DNS amplification attack.

See https://medium.com/@qratorlabs/the-memcached-amplification-attack-reaching-500-gbps-b439a7b83c98 or https://blog.cloudflare.com/memcrashed-major-amplification-attacks-from-port-11211/.

Thousands of unsecured memcached installations over the world, are part of DDoS attacks with power of few Tbps throughput :-( Our project was first victim in Czech Republic with power about 230 Gbps.

I know, it's primarily about server admins, but it's sad...

@dormando

This comment has been minimized.

Copy link
Member

@dormando dormando replied Feb 27, 2018

I know it isn't much solace but I've been aware of this for a couple days:
https://github.com/memcached/memcached/wiki/ReleaseNotes156
if you can get the source address of any server, you can also easily disable them:
https://twitter.com/dormando/status/968579781729009664
distro's and vendors should be shutting off UDP going forward.

@BrianAker

This comment has been minimized.

Copy link
Contributor Author

@BrianAker BrianAker replied Feb 28, 2018

Please sign in to comment.