miniupnpd: Work in IPv6 on system where PF_INET6 are restricted to IPv6 only
This commit is contained in:
parent
2a48074f45
commit
15682180a5
|
@ -2,6 +2,7 @@ $Id: Changelog.txt,v 1.362 2014/03/13 10:20:57 nanard Exp $
|
|||
|
||||
2014/03/10:
|
||||
Enable PCP by default.
|
||||
Work in IPv6 on system where PF_INET6 are restricted to IPv6 only
|
||||
|
||||
2014/03/09:
|
||||
IPv6 support in testgetifaddr
|
||||
|
|
|
@ -115,6 +115,7 @@ case $OS_NAME in
|
|||
FW=pf
|
||||
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
||||
OS_URL=http://www.openbsd.org/
|
||||
V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only`
|
||||
;;
|
||||
FreeBSD)
|
||||
VER=`grep '#define __FreeBSD_version' /usr/include/sys/param.h | awk '{print $3}'`
|
||||
|
@ -145,12 +146,14 @@ case $OS_NAME in
|
|||
fi
|
||||
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
||||
OS_URL=http://www.freebsd.org/
|
||||
V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only`
|
||||
;;
|
||||
pfSense)
|
||||
# we need to detect if PFRULE_INOUT_COUNTS macro is needed
|
||||
FW=pf
|
||||
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
||||
OS_URL=http://www.pfsense.com/
|
||||
V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only`
|
||||
;;
|
||||
NetBSD)
|
||||
if [ -f /etc/rc.subr ] && [ -f /etc/rc.conf ] ; then
|
||||
|
@ -308,6 +311,11 @@ case $FW in
|
|||
;;
|
||||
esac
|
||||
|
||||
# set V6SOCKETS_ARE_V6ONLY to 0 if it was not set above
|
||||
if [ -z "$V6SOCKETS_ARE_V6ONLY" ] ; then
|
||||
V6SOCKETS_ARE_V6ONLY=0
|
||||
fi
|
||||
|
||||
echo "Configuring compilation for [$OS_NAME] [$OS_VERSION] with [$FW] firewall software."
|
||||
echo "Please edit config.h for more compilation options."
|
||||
|
||||
|
@ -403,6 +411,15 @@ else
|
|||
fi
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* Define V6SOCKETS_ARE_V6ONLY if AF_INET6 sockets are restricted" >> ${CONFIGFILE}
|
||||
echo " * to IPv6 communications only. */" >> ${CONFIGFILE}
|
||||
if [ $V6SOCKETS_ARE_V6ONLY -eq 1 ] ; then
|
||||
echo "#define V6SOCKETS_ARE_V6ONLY" >> ${CONFIGFILE}
|
||||
else
|
||||
echo "/*#define V6SOCKETS_ARE_V6ONLY*/" >> ${CONFIGFILE}
|
||||
fi
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* Enable the support of IGD v2 specification." >> ${CONFIGFILE}
|
||||
echo " * This is not fully tested yet and can cause incompatibilities with some" >> ${CONFIGFILE}
|
||||
echo " * control points, so enable with care. */" >> ${CONFIGFILE}
|
||||
|
|
|
@ -112,7 +112,11 @@ volatile sig_atomic_t should_send_public_address_change_notif = 0;
|
|||
/* OpenAndConfHTTPSocket() :
|
||||
* setup the socket used to handle incoming HTTP connections. */
|
||||
static int
|
||||
#ifdef ENABLE_IPV6
|
||||
OpenAndConfHTTPSocket(unsigned short port, int ipv6)
|
||||
#else
|
||||
OpenAndConfHTTPSocket(unsigned short port)
|
||||
#endif
|
||||
{
|
||||
int s;
|
||||
int i = 1;
|
||||
|
@ -126,7 +130,7 @@ OpenAndConfHTTPSocket(unsigned short port)
|
|||
|
||||
if( (s = socket(
|
||||
#ifdef ENABLE_IPV6
|
||||
ipv6_enabled ? PF_INET6 : PF_INET,
|
||||
ipv6 ? PF_INET6 : PF_INET,
|
||||
#else
|
||||
PF_INET,
|
||||
#endif
|
||||
|
@ -155,7 +159,7 @@ OpenAndConfHTTPSocket(unsigned short port)
|
|||
}
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
if(ipv6_enabled)
|
||||
if(ipv6)
|
||||
{
|
||||
memset(&listenname6, 0, sizeof(struct sockaddr_in6));
|
||||
listenname6.sin6_family = AF_INET6;
|
||||
|
@ -179,7 +183,7 @@ OpenAndConfHTTPSocket(unsigned short port)
|
|||
|
||||
#ifdef ENABLE_IPV6
|
||||
if(bind(s,
|
||||
ipv6_enabled ? (struct sockaddr *)&listenname6 : (struct sockaddr *)&listenname4,
|
||||
ipv6 ? (struct sockaddr *)&listenname6 : (struct sockaddr *)&listenname4,
|
||||
listenname_len) < 0)
|
||||
#else
|
||||
if(bind(s, (struct sockaddr *)&listenname, listenname_len) < 0)
|
||||
|
@ -200,6 +204,84 @@ OpenAndConfHTTPSocket(unsigned short port)
|
|||
return s;
|
||||
}
|
||||
|
||||
static struct upnphttp *
|
||||
ProcessIncomingHTTP(int shttpl)
|
||||
{
|
||||
int shttp;
|
||||
socklen_t clientnamelen;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct sockaddr_storage clientname;
|
||||
clientnamelen = sizeof(struct sockaddr_storage);
|
||||
#else
|
||||
struct sockaddr_in clientname;
|
||||
clientnamelen = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen);
|
||||
if(shttp<0)
|
||||
{
|
||||
/* ignore EAGAIN, EWOULDBLOCK, EINTR, we just try again later */
|
||||
if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
|
||||
syslog(LOG_ERR, "accept(http): %m");
|
||||
}
|
||||
else
|
||||
{
|
||||
struct upnphttp * tmp = 0;
|
||||
char addr_str[64];
|
||||
|
||||
sockaddr_to_string((struct sockaddr *)&clientname, addr_str, sizeof(addr_str));
|
||||
syslog(LOG_INFO, "HTTP connection from %s", addr_str);
|
||||
if(get_lan_for_peer((struct sockaddr *)&clientname) == NULL)
|
||||
{
|
||||
/* The peer is not a LAN ! */
|
||||
syslog(LOG_WARNING,
|
||||
"HTTP peer %s is not from a LAN, closing the connection",
|
||||
addr_str);
|
||||
close(shttp);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create a new upnphttp object and add it to
|
||||
* the active upnphttp object list */
|
||||
tmp = New_upnphttp(shttp);
|
||||
if(tmp)
|
||||
{
|
||||
#ifdef ENABLE_IPV6
|
||||
if(clientname.ss_family == AF_INET)
|
||||
{
|
||||
tmp->clientaddr = ((struct sockaddr_in *)&clientname)->sin_addr;
|
||||
}
|
||||
else if(clientname.ss_family == AF_INET6)
|
||||
{
|
||||
struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&clientname;
|
||||
if(IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr))
|
||||
{
|
||||
memcpy(&tmp->clientaddr,
|
||||
&addr->sin6_addr.s6_addr[12],
|
||||
4);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp->ipv6 = 1;
|
||||
memcpy(&tmp->clientaddr_v6,
|
||||
&addr->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
}
|
||||
}
|
||||
#else
|
||||
tmp->clientaddr = clientname.sin_addr;
|
||||
#endif
|
||||
return tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
syslog(LOG_ERR, "New_upnphttp() failed");
|
||||
close(shttp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_NFQUEUE
|
||||
|
||||
int identify_ip_protocol(char *payload) {
|
||||
|
@ -1368,6 +1450,9 @@ main(int argc, char * * argv)
|
|||
{
|
||||
int i;
|
||||
int shttpl = -1; /* socket for HTTP */
|
||||
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
|
||||
int shttpl_v4 = -1; /* socket for HTTP (ipv4 only) */
|
||||
#endif
|
||||
int sudp = -1; /* IP v4 socket for receiving SSDP */
|
||||
#ifdef ENABLE_IPV6
|
||||
int sudpv6 = -1; /* IP v6 socket for receiving SSDP */
|
||||
|
@ -1459,7 +1544,11 @@ main(int argc, char * * argv)
|
|||
{
|
||||
|
||||
/* open socket for HTTP connections. Listen on the 1st LAN address */
|
||||
#ifdef ENABLE_IPV6
|
||||
shttpl = OpenAndConfHTTPSocket((v.port > 0) ? v.port : 0, 1);
|
||||
#else /* ENABLE_IPV6 */
|
||||
shttpl = OpenAndConfHTTPSocket((v.port > 0) ? v.port : 0);
|
||||
#endif /* ENABLE_IPV6 */
|
||||
if(shttpl < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING");
|
||||
|
@ -1475,6 +1564,14 @@ main(int argc, char * * argv)
|
|||
v.port = ntohs(sockinfo.sin_port);
|
||||
}
|
||||
syslog(LOG_NOTICE, "HTTP listening on port %d", v.port);
|
||||
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
|
||||
shttpl_v4 = OpenAndConfHTTPSocket(v.port, 0);
|
||||
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 */
|
||||
#ifdef ENABLE_IPV6
|
||||
if(find_ipv6_addr(NULL, ipv6_addr_for_http_with_brackets, sizeof(ipv6_addr_for_http_with_brackets)) > 0) {
|
||||
syslog(LOG_NOTICE, "HTTP IPv6 address given to control points : %s",
|
||||
|
@ -1692,6 +1789,13 @@ main(int argc, char * * argv)
|
|||
FD_SET(shttpl, &readset);
|
||||
max_fd = MAX( max_fd, shttpl);
|
||||
}
|
||||
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
|
||||
if (shttpl_v4 >= 0)
|
||||
{
|
||||
FD_SET(shttpl_v4, &readset);
|
||||
max_fd = MAX( max_fd, shttpl_v4);
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_IPV6
|
||||
if (sudpv6 >= 0)
|
||||
{
|
||||
|
@ -1930,79 +2034,24 @@ main(int argc, char * * argv)
|
|||
/* process incoming HTTP connections */
|
||||
if(shttpl >= 0 && FD_ISSET(shttpl, &readset))
|
||||
{
|
||||
int shttp;
|
||||
socklen_t clientnamelen;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct sockaddr_storage clientname;
|
||||
clientnamelen = sizeof(struct sockaddr_storage);
|
||||
#else
|
||||
struct sockaddr_in clientname;
|
||||
clientnamelen = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen);
|
||||
if(shttp<0)
|
||||
struct upnphttp * tmp;
|
||||
tmp = ProcessIncomingHTTP(shttpl);
|
||||
if(tmp)
|
||||
{
|
||||
/* ignore EAGAIN, EWOULDBLOCK, EINTR, we just try again later */
|
||||
if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
|
||||
syslog(LOG_ERR, "accept(http): %m");
|
||||
}
|
||||
else
|
||||
{
|
||||
struct upnphttp * tmp = 0;
|
||||
char addr_str[64];
|
||||
|
||||
sockaddr_to_string((struct sockaddr *)&clientname, addr_str, sizeof(addr_str));
|
||||
syslog(LOG_INFO, "HTTP connection from %s", addr_str);
|
||||
if(get_lan_for_peer((struct sockaddr *)&clientname) == NULL)
|
||||
{
|
||||
/* The peer is not a LAN ! */
|
||||
syslog(LOG_WARNING,
|
||||
"HTTP peer %s is not from a LAN, closing the connection",
|
||||
addr_str);
|
||||
close(shttp);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create a new upnphttp object and add it to
|
||||
* the active upnphttp object list */
|
||||
tmp = New_upnphttp(shttp);
|
||||
if(tmp)
|
||||
{
|
||||
#ifdef ENABLE_IPV6
|
||||
if(clientname.ss_family == AF_INET)
|
||||
{
|
||||
tmp->clientaddr = ((struct sockaddr_in *)&clientname)->sin_addr;
|
||||
}
|
||||
else if(clientname.ss_family == AF_INET6)
|
||||
{
|
||||
struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&clientname;
|
||||
if(IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr))
|
||||
{
|
||||
memcpy(&tmp->clientaddr,
|
||||
&addr->sin6_addr.s6_addr[12],
|
||||
4);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp->ipv6 = 1;
|
||||
memcpy(&tmp->clientaddr_v6,
|
||||
&addr->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
}
|
||||
}
|
||||
#else
|
||||
tmp->clientaddr = clientname.sin_addr;
|
||||
#endif
|
||||
LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
|
||||
}
|
||||
else
|
||||
{
|
||||
syslog(LOG_ERR, "New_upnphttp() failed");
|
||||
close(shttp);
|
||||
}
|
||||
}
|
||||
LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
|
||||
}
|
||||
}
|
||||
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
|
||||
if(shttpl_v4 >= 0 && FD_ISSET(shttpl_v4, &readset))
|
||||
{
|
||||
struct upnphttp * tmp;
|
||||
tmp = ProcessIncomingHTTP(shttpl_v4);
|
||||
if(tmp)
|
||||
{
|
||||
LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_NFQUEUE
|
||||
/* process NFQ packets */
|
||||
if(nfqh >= 0 && FD_ISSET(nfqh, &readset))
|
||||
|
@ -2052,6 +2101,9 @@ shutdown:
|
|||
|
||||
if (sudp >= 0) close(sudp);
|
||||
if (shttpl >= 0) close(shttpl);
|
||||
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
|
||||
if (shttpl_v4 >= 0) close(shttpl_v4);
|
||||
#endif
|
||||
#ifdef ENABLE_IPV6
|
||||
if (sudpv6 >= 0) close(sudpv6);
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue