miniupnpd: disable IPV6 if socket(PF_INET6) returns EAFNOSUPPORT

This commit is contained in:
Thomas Bernard 2014-05-22 01:38:18 +02:00
parent 9f78015a5b
commit 72463253dc

View File

@ -113,9 +113,9 @@ volatile sig_atomic_t should_send_public_address_change_notif = 0;
* setup the socket used to handle incoming HTTP connections. */ * setup the socket used to handle incoming HTTP connections. */
static int static int
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
OpenAndConfHTTPSocket(unsigned short port, int ipv6) OpenAndConfHTTPSocket(unsigned short * port, int ipv6)
#else #else
OpenAndConfHTTPSocket(unsigned short port) OpenAndConfHTTPSocket(unsigned short * port)
#endif #endif
{ {
int s; int s;
@ -128,13 +128,24 @@ OpenAndConfHTTPSocket(unsigned short port)
#endif #endif
socklen_t listenname_len; socklen_t listenname_len;
if( (s = socket( s = socket(
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
ipv6 ? PF_INET6 : PF_INET, ipv6 ? PF_INET6 : PF_INET,
#else #else
PF_INET, PF_INET,
#endif #endif
SOCK_STREAM, 0)) < 0) SOCK_STREAM, 0);
#ifdef ENABLE_IPV6
if(s < 0 && ipv6 && errno == EAFNOSUPPORT)
{
/* the system doesn't support IPV6 */
syslog(LOG_WARNING, "socket(PF_INET6, ...) failed with EAFNOSUPPORT, disabling IPv6");
SETFLAG(IPV6DISABLEDMASK);
ipv6 = 0;
s = socket(PF_INET, SOCK_STREAM, 0);
}
#endif
if(s < 0)
{ {
syslog(LOG_ERR, "socket(http): %m"); syslog(LOG_ERR, "socket(http): %m");
return -1; return -1;
@ -163,20 +174,20 @@ OpenAndConfHTTPSocket(unsigned short port)
{ {
memset(&listenname6, 0, sizeof(struct sockaddr_in6)); memset(&listenname6, 0, sizeof(struct sockaddr_in6));
listenname6.sin6_family = AF_INET6; listenname6.sin6_family = AF_INET6;
listenname6.sin6_port = htons(port); listenname6.sin6_port = htons(*port);
listenname6.sin6_addr = ipv6_bind_addr; listenname6.sin6_addr = ipv6_bind_addr;
listenname_len = sizeof(struct sockaddr_in6); listenname_len = sizeof(struct sockaddr_in6);
} else { } else {
memset(&listenname4, 0, sizeof(struct sockaddr_in)); memset(&listenname4, 0, sizeof(struct sockaddr_in));
listenname4.sin_family = AF_INET; listenname4.sin_family = AF_INET;
listenname4.sin_port = htons(port); listenname4.sin_port = htons(*port);
listenname4.sin_addr.s_addr = htonl(INADDR_ANY); listenname4.sin_addr.s_addr = htonl(INADDR_ANY);
listenname_len = sizeof(struct sockaddr_in); listenname_len = sizeof(struct sockaddr_in);
} }
#else #else
memset(&listenname, 0, sizeof(struct sockaddr_in)); memset(&listenname, 0, sizeof(struct sockaddr_in));
listenname.sin_family = AF_INET; listenname.sin_family = AF_INET;
listenname.sin_port = htons(port); listenname.sin_port = htons(*port);
listenname.sin_addr.s_addr = htonl(INADDR_ANY); listenname.sin_addr.s_addr = htonl(INADDR_ANY);
listenname_len = sizeof(struct sockaddr_in); listenname_len = sizeof(struct sockaddr_in);
#endif #endif
@ -201,6 +212,29 @@ OpenAndConfHTTPSocket(unsigned short port)
return -1; return -1;
} }
if(*port == 0) {
#ifdef ENABLE_IPV6
if(ipv6) {
struct sockaddr_in6 sockinfo;
socklen_t len = sizeof(struct sockaddr_in6);
if (getsockname(s, (struct sockaddr *)&sockinfo, &len) < 0) {
syslog(LOG_ERR, "getsockname(): %m");
} else {
*port = ntohs(sockinfo.sin6_port);
}
} else {
#endif /* ENABLE_IPV6 */
struct sockaddr_in sockinfo;
socklen_t len = sizeof(struct sockaddr_in);
if (getsockname(s, (struct sockaddr *)&sockinfo, &len) < 0) {
syslog(LOG_ERR, "getsockname(): %m");
} else {
*port = ntohs(sockinfo.sin_port);
}
#ifdef ENABLE_IPV6
}
#endif /* ENABLE_IPV6 */
}
return s; return s;
} }
@ -1592,79 +1626,49 @@ main(int argc, char * * argv)
if(GETFLAG(ENABLEUPNPMASK)) if(GETFLAG(ENABLEUPNPMASK))
{ {
unsigned short listen_port;
listen_port = (v.port > 0) ? v.port : 0;
/* open socket for HTTP connections. Listen on the 1st LAN address */ /* open socket for HTTP connections. Listen on the 1st LAN address */
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
shttpl = OpenAndConfHTTPSocket((v.port > 0) ? v.port : 0, 1); shttpl = OpenAndConfHTTPSocket(&listen_port, 1);
#else /* ENABLE_IPV6 */ #else /* ENABLE_IPV6 */
shttpl = OpenAndConfHTTPSocket((v.port > 0) ? v.port : 0); shttpl = OpenAndConfHTTPSocket(&listen_port);
#endif /* ENABLE_IPV6 */ #endif /* ENABLE_IPV6 */
if(shttpl < 0) if(shttpl < 0)
{ {
syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING"); syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING");
return 1; return 1;
} }
if(v.port <= 0) { v.port = listen_port;
#ifdef ENABLE_IPV6
struct sockaddr_in6 sockinfo;
socklen_t len = sizeof(struct sockaddr_in6);
if (getsockname(shttpl, (struct sockaddr *)&sockinfo, &len) < 0) {
syslog(LOG_ERR, "getsockname(): %m");
return 1;
}
v.port = ntohs(sockinfo.sin6_port);
#else /* ENABLE_IPV6 */
struct sockaddr_in sockinfo;
socklen_t len = sizeof(struct sockaddr_in);
if (getsockname(shttpl, (struct sockaddr *)&sockinfo, &len) < 0) {
syslog(LOG_ERR, "getsockname(): %m");
return 1;
}
v.port = ntohs(sockinfo.sin_port);
#endif /* ENABLE_IPV6 */
}
syslog(LOG_NOTICE, "HTTP listening on port %d", v.port); syslog(LOG_NOTICE, "HTTP listening on port %d", v.port);
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6) #if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
shttpl_v4 = OpenAndConfHTTPSocket(v.port, 0); if(!GETFLAG(IPV6DISABLEDMASK))
if(shttpl_v4 < 0)
{ {
syslog(LOG_ERR, "Failed to open socket for HTTP on port %hu (IPv4). EXITING", v.port); shttpl_v4 = OpenAndConfHTTPSocket(&listen_port, 0);
return 1; if(shttpl_v4 < 0)
{
syslog(LOG_ERR, "Failed to open socket for HTTP on port %hu (IPv4). EXITING", v.port);
return 1;
}
} }
#endif /* V6SOCKETS_ARE_V6ONLY */ #endif /* V6SOCKETS_ARE_V6ONLY */
#ifdef ENABLE_HTTPS #ifdef ENABLE_HTTPS
/* https */ /* https */
listen_port = (v.https_port > 0) ? v.https_port : 0;
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
shttpsl = OpenAndConfHTTPSocket((v.https_port > 0) ? v.https_port : 0, 1); shttpsl = OpenAndConfHTTPSocket(&listen_port, 1);
#else /* ENABLE_IPV6 */ #else /* ENABLE_IPV6 */
shttpsl = OpenAndConfHTTPSocket((v.https_port > 0) ? v.https_port : 0); shttpsl = OpenAndConfHTTPSocket(&listen_port);
#endif /* ENABLE_IPV6 */ #endif /* ENABLE_IPV6 */
if(shttpl < 0) if(shttpl < 0)
{ {
syslog(LOG_ERR, "Failed to open socket for HTTPS. EXITING"); syslog(LOG_ERR, "Failed to open socket for HTTPS. EXITING");
return 1; return 1;
} }
if(v.https_port <= 0) { v.https_port = listen_port;
#ifdef ENABLE_IPV6
struct sockaddr_in6 sockinfo;
socklen_t len = sizeof(struct sockaddr_in6);
if (getsockname(shttpsl, (struct sockaddr *)&sockinfo, &len) < 0) {
syslog(LOG_ERR, "getsockname(): %m");
return 1;
}
v.https_port = ntohs(sockinfo.sin6_port);
#else /* ENABLE_IPV6 */
struct sockaddr_in sockinfo;
socklen_t len = sizeof(struct sockaddr_in);
if (getsockname(shttpsl, (struct sockaddr *)&sockinfo, &len) < 0) {
syslog(LOG_ERR, "getsockname(): %m");
return 1;
}
v.https_port = ntohs(sockinfo.sin_port);
#endif /* ENABLE_IPV6 */
}
syslog(LOG_NOTICE, "HTTPS listening on port %d", v.https_port); syslog(LOG_NOTICE, "HTTPS listening on port %d", v.https_port);
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6) #if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
shttpsl_v4 = OpenAndConfHTTPSocket(v.https_port, 0); shttpsl_v4 = OpenAndConfHTTPSocket(&listen_port, 0);
if(shttpsl_v4 < 0) if(shttpsl_v4 < 0)
{ {
syslog(LOG_ERR, "Failed to open socket for HTTPS on port %hu (IPv4). EXITING", v.https_port); syslog(LOG_ERR, "Failed to open socket for HTTPS on port %hu (IPv4). EXITING", v.https_port);