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 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 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 replied Feb 28, 2018

Please sign in to comment.
You can’t perform that action at this time.