diff options
author | Tim Waugh <twaugh@redhat.com> | 2014-11-17 17:07:07 +0000 |
---|---|---|
committer | Tim Waugh <twaugh@redhat.com> | 2014-11-17 17:07:07 +0000 |
commit | 6ae42df65141ccb49c875bda45b8f5ae9fa60c28 (patch) | |
tree | 4d3931fecec16edbf6f1aa8b7ea81a230775f674 /common | |
parent | 698371a65002c8785c34481635044fddc217d3f1 (diff) | |
download | tigervnc-6ae42df65141ccb49c875bda45b8f5ae9fa60c28.tar.gz tigervnc-6ae42df65141ccb49c875bda45b8f5ae9fa60c28.zip |
TcpSocket: IPv6 handling throughout (#68).
Diffstat (limited to 'common')
-rw-r--r-- | common/network/TcpSocket.cxx | 119 |
1 files changed, 100 insertions, 19 deletions
diff --git a/common/network/TcpSocket.cxx b/common/network/TcpSocket.cxx index 72f1545d..3129a93e 100644 --- a/common/network/TcpSocket.cxx +++ b/common/network/TcpSocket.cxx @@ -239,14 +239,43 @@ int TcpSocket::getMyPort() { } char* TcpSocket::getPeerAddress() { - struct sockaddr_in info; - struct in_addr addr; - socklen_t info_size = sizeof(info); + vnc_sockaddr_t sa; + socklen_t sa_size = sizeof(sa); + const void *addr; +#if defined(HAVE_GETADDRINFO) && defined(HAVE_INET_PTON) + char buffer[INET6_ADDRSTRLEN]; +#else + char buffer[46]; +#endif /* defined(HAVE_GETADDRINFO) && defined(HAVE_INET_PTON) */ - getpeername(getFd(), (struct sockaddr *)&info, &info_size); - memcpy(&addr, &info.sin_addr, sizeof(addr)); + if (getpeername(getFd(), &sa.u.sa, &sa_size) != 0) { + vlog.error("unable to get peer name for socket"); + return rfb::strDup(""); + } + + switch (sa.u.sa.sa_family) { +#ifdef HAVE_GETADDRINFO + case AF_INET6: + addr = &sa.u.sin6.sin6_addr; + break; +#endif /* HAVE_GETADDRINFO */ + + default: + addr = &sa.u.sin.sin_addr; + break; + } + +#ifdef HAVE_INET_PTON + const char* name = inet_ntop(sa.u.sa.sa_family, addr, + buffer, sizeof (buffer)); +#else + if (sa.u.sa.sa_family != AF_INET) { + vlog.error("unable to convert non-IPv4 address to string"); + return rfb::strDup(""); + } char* name = inet_ntoa(addr); +#endif /* HAVE_INET_PTON */ if (name) { return rfb::strDup(name); } else { @@ -255,11 +284,20 @@ char* TcpSocket::getPeerAddress() { } int TcpSocket::getPeerPort() { - struct sockaddr_in info; - socklen_t info_size = sizeof(info); + vnc_sockaddr_t sa; + socklen_t sa_size = sizeof(sa); - getpeername(getFd(), (struct sockaddr *)&info, &info_size); - return ntohs(info.sin_port); + getpeername(getFd(), &sa.u.sa, &sa_size); + + switch (sa.u.sa.sa_family) { +#ifdef HAVE_GETADDRINFO + case AF_INET6: + return ntohs(sa.u.sin6.sin6_port); +#endif /* HAVE_GETADDRINFO */ + + default: + return ntohs(sa.u.sin.sin_port); + } } char* TcpSocket::getPeerEndpoint() { @@ -326,25 +364,34 @@ bool TcpSocket::cork(int sock, bool enable) { bool TcpSocket::isSocket(int sock) { - struct sockaddr_in info; - socklen_t info_size = sizeof(info); - return getsockname(sock, (struct sockaddr *)&info, &info_size) >= 0; + vnc_sockaddr_t sa; + socklen_t sa_size = sizeof(sa); + return getsockname(sock, &sa.u.sa, &sa_size) >= 0; } bool TcpSocket::isConnected(int sock) { - struct sockaddr_in info; - socklen_t info_size = sizeof(info); - return getpeername(sock, (struct sockaddr *)&info, &info_size) >= 0; + vnc_sockaddr_t sa; + socklen_t sa_size = sizeof(sa); + return getpeername(sock, &sa.u.sa, &sa_size) >= 0; } int TcpSocket::getSockPort(int sock) { - struct sockaddr_in info; - socklen_t info_size = sizeof(info); - if (getsockname(sock, (struct sockaddr *)&info, &info_size) < 0) + vnc_sockaddr_t sa; + socklen_t sa_size = sizeof(sa); + if (getsockname(sock, &sa.u.sa, &sa_size) < 0) return 0; - return ntohs(info.sin_port); + + switch (sa.u.sa.sa_family) { +#ifdef HAVE_GETADDRINFO + case AF_INET6: + return ntohs(sa.u.sin6.sin6_port); +#endif /* HAVE_GETADDRINFO */ + + default: + return ntohs(sa.u.sin.sin_port); + } } @@ -515,6 +562,30 @@ TcpListener::accept() { } void TcpListener::getMyAddresses(std::list<char*>* result) { +#if defined(HAVE_GETADDRINFO) && defined(HAVE_INET_PTON) + vnc_sockaddr_t sa; + struct addrinfo *ai, *current, hints; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + if ((getaddrinfo(NULL, NULL, &hints, &ai)) != 0) + return; + + for (current= ai; current != NULL; current = current->ai_next) { + if (current->ai_family != AF_INET && current->ai_family != AF_INET6) + continue; + + char *addr = new char[INET6_ADDRSTRLEN]; + inet_ntop(current->ai_family, current->ai_addr, addr, INET6_ADDRSTRLEN); + result->push_back(addr); + } + freeaddrinfo(ai); +#else const hostent* addrs = gethostbyname(0); if (addrs == 0) throw rdr::SystemException("gethostbyname", errorNumber); @@ -526,6 +597,7 @@ void TcpListener::getMyAddresses(std::list<char*>* result) { strcpy(addr, addrC); result->push_back(addr); } +#endif /* defined(HAVE_GETADDRINFO) && defined(HAVE_INET_PTON) */ } int TcpListener::getMyPort() { @@ -559,6 +631,15 @@ bool TcpFilter::verifyConnection(Socket* s) { rfb::CharArray name; +#ifdef HAVE_GETADDRINFO + vnc_sockaddr_t sa; + socklen_t sa_size = sizeof(sa); + if (getpeername(s->getFd(), &sa.u.sa, &sa_size) != 0 || + sa.u.sa.sa_family != AF_INET) + /* Matching only works for IPv4 */ + return false; +#endif /* HAVE_GETADDRINFO */ + name.buf = s->getPeerAddress(); std::list<TcpFilter::Pattern>::iterator i; for (i=filter.begin(); i!=filter.end(); i++) { |