diff --git a/redis.conf b/redis.conf index 119f7b6f9..4caa70f38 100644 --- a/redis.conf +++ b/redis.conf @@ -49,23 +49,30 @@ # for connections from all available network interfaces on the host machine. # It is possible to listen to just one or multiple selected interfaces using # the "bind" configuration directive, followed by one or more IP addresses. +# Each address can be prefixed by "-", which means that redis will not fail to +# start if the address is not available. Being not available only refers to +# addresses that does not correspond to any network interfece. Addresses that +# are already in use will always fail, and unsupported protocols will always BE +# silently skipped. # # Examples: # -# bind 192.168.1.100 10.0.0.1 -# bind 127.0.0.1 ::1 +# bind 192.168.1.100 10.0.0.1 # listens on two specific IPv4 addresses +# bind 127.0.0.1 ::1 # listens on loopback IPv4 and IPv6 +# bind * -::* # like the default, all available interfaces # # ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the # internet, binding to all the interfaces is dangerous and will expose the # instance to everybody on the internet. So by default we uncomment the # following bind directive, that will force Redis to listen only on the -# IPv4 loopback interface address (this means Redis will only be able to -# accept client connections from the same host that it is running on). +# IPv4 and IPv6 (if available) loopback interface addresses (this means Redis +# will only be able to accept client connections from the same host that it is +# running on). # # IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES # JUST COMMENT OUT THE FOLLOWING LINE. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -bind 127.0.0.1 +bind 127.0.0.1 -::1 # Protected mode is a layer of security protection, in order to avoid that # Redis instances left open on the internet are accessed and exploited. diff --git a/src/anet.c b/src/anet.c index 46ea7e145..e9615a128 100644 --- a/src/anet.c +++ b/src/anet.c @@ -487,6 +487,10 @@ static int _anetTcpServer(char *err, int port, char *bindaddr, int af, int backl hints.ai_family = af; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; /* No effect if bindaddr != NULL */ + if (bindaddr && !strcmp("*", bindaddr)) + bindaddr = NULL; + if (af == AF_INET6 && bindaddr && !strcmp("::*", bindaddr)) + bindaddr = NULL; if ((rv = getaddrinfo(bindaddr,_port,&hints,&servinfo)) != 0) { anetSetError(err, "%s", gai_strerror(rv)); diff --git a/src/server.c b/src/server.c index bb035f795..cd45dd837 100644 --- a/src/server.c +++ b/src/server.c @@ -2799,59 +2799,37 @@ void checkTcpBacklogSettings(void) { * one of the IPv4 or IPv6 protocols. */ int listenToPort(int port, int *fds, int *count) { int j; + char **bindaddr = server.bindaddr; + int bindaddr_count = server.bindaddr_count; + char *default_bindaddr[2] = {"*", "-::*"}; - /* Force binding of 0.0.0.0 if no bind address is specified, always - * entering the loop if j == 0. */ - if (server.bindaddr_count == 0) server.bindaddr[0] = NULL; - for (j = 0; j < server.bindaddr_count || j == 0; j++) { - if (server.bindaddr[j] == NULL) { - int unsupported = 0; - /* Bind * for both IPv6 and IPv4, we enter here only if - * server.bindaddr_count == 0. */ - fds[*count] = anetTcp6Server(server.neterr,port,NULL, - server.tcp_backlog); - if (fds[*count] != ANET_ERR) { - anetNonBlock(NULL,fds[*count]); - (*count)++; - } else if (errno == EAFNOSUPPORT) { - unsupported++; - serverLog(LL_WARNING,"Not listening to IPv6: unsupported"); - } + /* Force binding of 0.0.0.0 if no bind address is specified. */ + if (server.bindaddr_count == 0) { + bindaddr_count = 2; + bindaddr = default_bindaddr; + } - if (*count == 1 || unsupported) { - /* Bind the IPv4 address as well. */ - fds[*count] = anetTcpServer(server.neterr,port,NULL, - server.tcp_backlog); - if (fds[*count] != ANET_ERR) { - anetNonBlock(NULL,fds[*count]); - (*count)++; - } else if (errno == EAFNOSUPPORT) { - unsupported++; - serverLog(LL_WARNING,"Not listening to IPv4: unsupported"); - } - } - /* Exit the loop if we were able to bind * on IPv4 and IPv6, - * otherwise fds[*count] will be ANET_ERR and we'll print an - * error and return to the caller with an error. */ - if (*count + unsupported == 2) break; - } else if (strchr(server.bindaddr[j],':')) { + for (j = 0; j < bindaddr_count; j++) { + char* addr = bindaddr[j]; + int optional = *addr == '-'; + if (optional) addr++; + if (strchr(addr,':')) { /* Bind IPv6 address. */ - fds[*count] = anetTcp6Server(server.neterr,port,server.bindaddr[j], - server.tcp_backlog); + fds[*count] = anetTcp6Server(server.neterr,port,addr,server.tcp_backlog); } else { /* Bind IPv4 address. */ - fds[*count] = anetTcpServer(server.neterr,port,server.bindaddr[j], - server.tcp_backlog); + fds[*count] = anetTcpServer(server.neterr,port,addr,server.tcp_backlog); } if (fds[*count] == ANET_ERR) { serverLog(LL_WARNING, "Could not create server TCP listening socket %s:%d: %s", - server.bindaddr[j] ? server.bindaddr[j] : "*", - port, server.neterr); - if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || - errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || - errno == EAFNOSUPPORT || errno == EADDRNOTAVAIL) - continue; + addr, port, server.neterr); + if (errno == EADDRNOTAVAIL && optional) + continue; + if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || + errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || + errno == EAFNOSUPPORT) + continue; return C_ERR; } anetNonBlock(NULL,fds[*count]);