aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nxcomp/ChannelEndPoint.cpp143
-rw-r--r--nxcomp/ChannelEndPoint.h11
-rw-r--r--nxcomp/Loop.cpp675
3 files changed, 607 insertions, 222 deletions
diff --git a/nxcomp/ChannelEndPoint.cpp b/nxcomp/ChannelEndPoint.cpp
index cb35e52d2..3e3053927 100644
--- a/nxcomp/ChannelEndPoint.cpp
+++ b/nxcomp/ChannelEndPoint.cpp
@@ -24,6 +24,7 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
+#include <sys/stat.h>
#include "ChannelEndPoint.h"
@@ -31,8 +32,21 @@
ChannelEndPoint::ChannelEndPoint(const char *spec)
: defaultTCPPort_(0), defaultTCPInterface_(0),
- defaultUnixPath_(NULL) {
- spec_ = (spec ? strdup(spec) : NULL);
+ defaultUnixPath_(NULL), spec_(NULL) {
+ setSpec(spec);
+}
+
+ChannelEndPoint::~ChannelEndPoint()
+{
+ char *unixPath = NULL;
+
+ if (getUnixPath(&unixPath))
+ {
+ struct stat st;
+ lstat(unixPath, &st);
+ if(S_ISSOCK(st.st_mode))
+ unlink(unixPath);
+ }
}
void
@@ -40,21 +54,92 @@ ChannelEndPoint::setSpec(const char *spec) {
if (spec_) free(spec_);
if (spec && strlen(spec))
+ {
spec_ = strdup(spec);
+ isUnix_ = getUnixPath();
+ isTCP_ = getTCPHostAndPort();
+ }
else
+ {
spec_ = NULL;
+ isUnix_ = false;
+ isTCP_ = false;
+ }
}
void
-ChannelEndPoint::setSpec(int port) {
+ChannelEndPoint::setSpec(long port) {
if (port >= 0) {
char tmp[20];
- sprintf(tmp, "%d", port);
+ sprintf(tmp, "%ld", port);
setSpec(tmp);
}
+ else {
+ disable();
+ }
+}
+
+void
+ChannelEndPoint::setSpec(const char *hostName, long port) {
+ int length;
+
+ if (spec_) free(spec_);
+ isUnix_ = false;
+ isTCP_ = false;
+
+ if (hostName && strlen(hostName) && port >= 1)
+ {
+ length = snprintf(NULL, 0, "tcp:%s:%ld", hostName, port);
+ spec_ = (char *)calloc(length + 1, sizeof(char));
+ snprintf(spec_, length+1, "tcp:%s:%ld", hostName, port);
+ isTCP_ = true;
+ }
else setSpec((char*)NULL);
}
+bool
+ChannelEndPoint::getSpec(char **socketUri) const {
+
+ if (socketUri) *socketUri = NULL;
+
+ char *unixPath = NULL;
+ char *hostName = NULL;
+ long port = -1;
+
+ char *newSocketUri = NULL;
+ int length = -1;
+
+ if (getUnixPath(&unixPath))
+ {
+ length = snprintf(NULL, 0, "unix:%s", unixPath);
+ }
+ else if (getTCPHostAndPort(&hostName, &port))
+ {
+ length = snprintf(NULL, 0, "tcp:%s:%ld", hostName, port);
+ }
+
+ if (length > 0)
+ {
+ newSocketUri = (char *)calloc(length + 1, sizeof(char));
+ if (isUnixSocket())
+ snprintf(newSocketUri, length+1, "unix:%s", unixPath);
+ else
+ snprintf(newSocketUri, length+1, "tcp:%s:%ld", hostName, port);
+
+ if (socketUri)
+ *socketUri = strdup(newSocketUri);
+ }
+
+ free(newSocketUri);
+ free(unixPath);
+ free(hostName);
+
+ if (*socketUri != '\0')
+ return true;
+
+ return false;
+}
+
void
ChannelEndPoint::setDefaultTCPPort(long port) {
defaultTCPPort_ = port;
@@ -76,10 +161,12 @@ ChannelEndPoint::setDefaultUnixPath(char *path) {
}
void
-ChannelEndPoint::disable() { setSpec("0"); }
+ChannelEndPoint::disable() {
+ setSpec("0");
+}
bool
-ChannelEndPoint::specIsPort(long *port) const {
+ChannelEndPoint::getPort(long *port) const {
if (port) *port = 0;
long p = -1;
if (spec_) {
@@ -101,7 +188,7 @@ ChannelEndPoint::getUnixPath(char **unixPath) const {
long p;
char *path = NULL;
- if (specIsPort(&p)) {
+ if (getPort(&p)) {
if (p != 1) return false;
}
else if (spec_ && (strncmp("unix:", spec_, 5) == 0)) {
@@ -122,6 +209,11 @@ ChannelEndPoint::getUnixPath(char **unixPath) const {
return true;
}
+bool
+ChannelEndPoint::isUnixSocket() const {
+ return isUnix_;
+}
+
// FIXME!!!
static const char *
getComputerName() {
@@ -158,7 +250,7 @@ ChannelEndPoint::getTCPHostAndPort(char **host, long *port) const {
if (host) *host = NULL;
if (port) *port = 0;
- if (specIsPort(&p)) {
+ if (getPort(&p)) {
h_len = 0;
}
else if (spec_ && (strncmp("tcp:", spec_, 4) == 0)) {
@@ -194,8 +286,8 @@ ChannelEndPoint::getTCPHostAndPort(char **host, long *port) const {
}
bool
-ChannelEndPoint::enabled() const {
- return (getUnixPath() || getTCPHostAndPort());
+ChannelEndPoint::isTCPSocket() const {
+ return isTCP_;
}
long ChannelEndPoint::getTCPPort() const {
@@ -205,8 +297,15 @@ long ChannelEndPoint::getTCPPort() const {
}
bool
+ChannelEndPoint::enabled() const {
+ return (isUnixSocket() || isTCPSocket());
+}
+
+bool
ChannelEndPoint::validateSpec() {
- return (specIsPort() || getUnixPath() || getTCPHostAndPort());
+ isTCP_ = getTCPHostAndPort();
+ isUnix_ = getUnixPath();
+ return ( getPort() || isUnix_ || isTCP_ );
}
ChannelEndPoint &ChannelEndPoint::operator=(const ChannelEndPoint &other) {
@@ -219,26 +318,24 @@ ChannelEndPoint &ChannelEndPoint::operator=(const ChannelEndPoint &other) {
old = spec_;
spec_ = (other.spec_ ? strdup(other.spec_) : NULL);
free(old);
+ isUnix_ = getUnixPath();
+ isTCP_ = getTCPHostAndPort();
return *this;
}
std::ostream& operator<<(std::ostream& os, const ChannelEndPoint& endPoint) {
if (endPoint.enabled()) {
- char *unixPath, *host;
- long port;
- if (endPoint.getUnixPath(&unixPath)) {
- os << "unix:" << unixPath;
- free(unixPath);
+ char* endPointSpec = NULL;
+ if (endPoint.getSpec(&endPointSpec))
+ {
+ os << endPointSpec;
+ free(endPointSpec);
}
- else if (endPoint.getTCPHostAndPort(&host, &port)) {
- os << "tcp:" << host << ":" << port;
- free(host);
- }
- else {
+ else
os << "(invalid)";
- }
}
- else {
+ else
+ {
os << "(disabled)";
}
return os;
diff --git a/nxcomp/ChannelEndPoint.h b/nxcomp/ChannelEndPoint.h
index 5b4e75345..901952e37 100644
--- a/nxcomp/ChannelEndPoint.h
+++ b/nxcomp/ChannelEndPoint.h
@@ -33,25 +33,32 @@ class ChannelEndPoint
int defaultTCPInterface_; // 0=localhost, otherwise IP of public interface.
char *defaultUnixPath_;
char *spec_;
+ bool isUnix_;
+ bool isTCP_;
- bool specIsPort(long *port = NULL) const;
+ bool getPort(long *port = NULL) const;
public:
ChannelEndPoint(const char *spec = NULL);
+ ~ChannelEndPoint();
ChannelEndPoint &operator=(const ChannelEndPoint &other);
bool enabled() const;
bool disabled() { return !enabled(); }
void disable();
void setSpec(const char *spec);
- void setSpec(int port);
+ void setSpec(long port);
+ void setSpec(const char *hostName, long port);
+ bool getSpec(char **socketUri) const;
void setDefaultTCPPort(long port);
void setDefaultTCPInterface(int publicInterface);
void setDefaultUnixPath(char *path);
bool getUnixPath(char **path = NULL) const;
+ bool isUnixSocket() const;
bool getTCPHostAndPort(char **hostname = NULL, long *port = NULL) const;
long getTCPPort() const;
+ bool isTCPSocket() const;
bool validateSpec();
};
diff --git a/nxcomp/Loop.cpp b/nxcomp/Loop.cpp
index 450c477c6..6bec5e30d 100644
--- a/nxcomp/Loop.cpp
+++ b/nxcomp/Loop.cpp
@@ -239,7 +239,7 @@ struct sockaddr_un
// should connect to remote.
//
-#define WE_INITIATE_CONNECTION (*connectHost != '\0')
+#define WE_INITIATE_CONNECTION (connectSocket.enabled())
//
// Is true if we must provide our credentials
@@ -255,7 +255,7 @@ struct sockaddr_un
//
#define WE_LISTEN_FORWARDER (control -> ProxyMode == proxy_server && \
- listenPort != -1)
+ listenSocket.enabled())
//
// You must define FLUSH in Misc.h if
@@ -440,7 +440,7 @@ static int SetupDisplaySocket(int &xServerAddrFamily, sockaddr *&xServerAddr,
static int ListenConnection(ChannelEndPoint &endPoint, const char *label);
static int ListenConnectionTCP(const char *host, long port, const char *label);
-static int ListenConnectionUnix(const char *unixPath, const char *label);
+static int ListenConnectionUnix(const char *path, const char *label);
static int ListenConnectionAny(sockaddr *addr, socklen_t addrlen, const char *label);
static int AcceptConnection(int fd, int domain, const char *label);
@@ -448,8 +448,11 @@ static int AcceptConnection(int fd, int domain, const char *label);
// Other convenience functions.
//
-static int WaitForRemote(int portNum);
-static int ConnectToRemote(const char *const hostName, int portNum);
+static int PrepareProxyConnectionTCP(char** hostName, long int* portNum, int* timeout, int* proxyFD, int* reason);
+static int PrepareProxyConnectionUnix(char** path, int* timeout, int* proxyFD, int* reason);
+
+static int WaitForRemote(ChannelEndPoint &socketAddress);
+static int ConnectToRemote(ChannelEndPoint &socketAddress);
static int SendProxyOptions(int fd);
static int SendProxyCaches(int fd);
@@ -514,7 +517,7 @@ static int ParsePackOption(const char *opt);
// given on the command line.
//
-static int ParseHostOption(const char *opt, char *host, int &port);
+static int ParseHostOption(const char *opt, char *host, long &port);
//
// Translate a font server port specification
@@ -944,7 +947,6 @@ static char unixSocketName[DEFAULT_STRING_LENGTH] = { 0 };
// Other parameters.
//
-static char connectHost[DEFAULT_STRING_LENGTH] = { 0 };
static char acceptHost[DEFAULT_STRING_LENGTH] = { 0 };
static char displayHost[DEFAULT_STRING_LENGTH] = { 0 };
static char authCookie[DEFAULT_STRING_LENGTH] = { 0 };
@@ -963,13 +965,19 @@ static sockaddr *xServerAddr = NULL;
static unsigned int xServerAddrLength = 0;
//
-// The port where the local proxy will await
-// the peer connection or where the remote
-// proxy will be contacted.
+// The representation of a Unix socket path or
+// a bind address, denoting where the local proxy
+// will await the peer connection.
+//
+
+static ChannelEndPoint listenSocket;
+
+//
+// The TCP host and port or Unix file socket where
+// the remote proxy will be contacted.
//
-static int listenPort = -1;
-static int connectPort = -1;
+static ChannelEndPoint connectSocket;
//
// Helper channels are disabled by default.
@@ -3355,58 +3363,88 @@ int InitBeforeNegotiation()
int SetupProxyConnection()
{
+
if (proxyFD == -1)
{
+
+ char *socketUri = NULL;
+
+ // Let's make sure, the default value for listenSocket is properly set. Doing this
+ // here, because we have to make sure that we call it after the connectSocket
+ // declaration is really really complete.
+
+ if (listenSocket.disabled() && connectSocket.disabled())
+ {
+ char listenPortValue[20] = { 0 };
+ sprintf(listenPortValue, "%ld", (long)(proxyPort + DEFAULT_NX_PROXY_PORT_OFFSET));
+
+ SetAndValidateChannelEndPointArg("local", "listen", listenPortValue, listenSocket);
+ }
+
+ #ifdef TEST
+ connectSocket.getSpec(&socketUri);
+ *logofs << "Loop: connectSocket is "<< ( connectSocket.enabled() ? "enabled" : "disabled") << ". "
+ << "The socket URI is '"<< ( socketUri != NULL ? socketUri : "<unset>") << "'.\n" << logofs_flush;
+ listenSocket.getSpec(&socketUri);
+ *logofs << "Loop: listenSocket is "<< ( listenSocket.enabled() ? "enabled" : "disabled") << ". "
+ << "The socket URI is '"<< ( socketUri != NULL ? socketUri : "<unset>") << "'.\n" << logofs_flush;
+ free(socketUri);
+ socketUri = NULL;
+ #endif
+
if (WE_INITIATE_CONNECTION)
{
- if (connectPort < 0)
+ if (connectSocket.getSpec(&socketUri))
{
- connectPort = DEFAULT_NX_PROXY_PORT_OFFSET + proxyPort;
- }
-
- #ifdef TEST
- *logofs << "Loop: Going to connect to " << connectHost
- << ":" << connectPort << ".\n" << logofs_flush;
- #endif
+ #ifdef TEST
+ *logofs << "Loop: Going to connect to '" << socketUri
+ << "'.\n" << logofs_flush;
+ #endif
+ free(socketUri);
- proxyFD = ConnectToRemote(connectHost, connectPort);
+ proxyFD = ConnectToRemote(connectSocket);
- #ifdef TEST
- *logofs << "Loop: Connected to remote proxy on FD#"
- << proxyFD << ".\n" << logofs_flush;
- #endif
+ #ifdef TEST
+ *logofs << "Loop: Connected to remote proxy on FD#"
+ << proxyFD << ".\n" << logofs_flush;
+ #endif
- cerr << "Info" << ": Connection to remote proxy '" << connectHost
- << ":" << connectPort << "' established.\n";
+ cerr << "Info" << ": Connected to remote proxy on FD#"
+ << proxyFD << ".\n";
+ }
}
else
{
- if (listenPort < 0)
+
+ if (listenSocket.isTCPSocket() && (listenSocket.getTCPPort() < 0))
{
- listenPort = DEFAULT_NX_PROXY_PORT_OFFSET + proxyPort;
+ listenSocket.setSpec(DEFAULT_NX_PROXY_PORT_OFFSET + proxyPort);
}
- #ifdef TEST
- *logofs << "Loop: Going to wait for connection on port "
- << listenPort << ".\n" << logofs_flush;
- #endif
+ if (listenSocket.getSpec(&socketUri))
+ {
+ #ifdef TEST
+ *logofs << "Loop: Going to wait for connection at '"
+ << socketUri << "'.\n" << logofs_flush;
+ #endif
+ free(socketUri);
- proxyFD = WaitForRemote(listenPort);
+ proxyFD = WaitForRemote(listenSocket);
- #ifdef TEST
+ #ifdef TEST
+ if (WE_LISTEN_FORWARDER)
+ {
+ *logofs << "Loop: Connected to remote forwarder on FD#"
+ << proxyFD << ".\n" << logofs_flush;
+ }
+ else
+ {
+ *logofs << "Loop: Connected to remote proxy on FD#"
+ << proxyFD << ".\n" << logofs_flush;
+ }
+ #endif
- if (WE_LISTEN_FORWARDER)
- {
- *logofs << "Loop: Connected to remote forwarder on FD#"
- << proxyFD << ".\n" << logofs_flush;
}
- else
- {
- *logofs << "Loop: Connected to remote proxy on FD#"
- << proxyFD << ".\n" << logofs_flush;
- }
-
- #endif
}
}
#ifdef TEST
@@ -3422,8 +3460,11 @@ int SetupProxyConnection()
// to reduce startup time. Option will
// later be disabled if needed.
//
+ // either listenSocket or connectSocket is used here...
+
+ if(listenSocket.isTCPSocket() || connectSocket.isTCPSocket())
- SetNoDelay(proxyFD, 1);
+ SetNoDelay(proxyFD, 1);
//
// We need non-blocking input since the
@@ -4404,11 +4445,13 @@ int ListenConnectionAny(sockaddr *addr, socklen_t addrlen, const char *label)
goto SetupSocketError;
}
- if (SetReuseAddress(newFD) < 0)
- {
- // SetReuseAddress already warns with an error
- goto SetupSocketError;
- }
+
+ if (addr->sa_family == AF_INET)
+ if (SetReuseAddress(newFD) < 0)
+ {
+ // SetReuseAddress already warns with an error
+ goto SetupSocketError;
+ }
if (bind(newFD, addr, addrlen) == -1)
{
@@ -4427,12 +4470,12 @@ int ListenConnectionAny(sockaddr *addr, socklen_t addrlen, const char *label)
if (listen(newFD, 8) == -1)
{
#ifdef PANIC
- *logofs << "Loop: PANIC! Call to bind failed for " << label
+ *logofs << "Loop: PANIC! Call to listen failed for " << label
<< ". Error is " << EGET()
<< " '" << ESTR() << "'.\n" << logofs_flush;
#endif
- cerr << "Error" << ": Call to bind failed for " << label
+ cerr << "Error" << ": Call to listen failed for " << label
<< ". Error is " << EGET()
<< " '" << ESTR() << "'.\n";
@@ -5445,7 +5488,6 @@ void CleanupLocal()
*unixSocketName = '\0';
- *connectHost = '\0';
*acceptHost = '\0';
*displayHost = '\0';
*authCookie = '\0';
@@ -5460,8 +5502,8 @@ void CleanupLocal()
xServerAddr = NULL;
- listenPort = -1;
- connectPort = -1;
+ listenSocket.disable();
+ connectSocket.disable();
cupsPort.disable();
auxPort.disable();
@@ -6592,62 +6634,79 @@ void ResetTimer()
}
//
-// Open TCP socket to listen for remote proxy and
-// block until remote connects. If successful close
-// the listening socket and return FD on which the
-// other party is connected.
+// Open TCP or UNIX file socket to listen for remote proxy
+// and block until remote connects. If successful close
+// the listening socket and return FD on which the other
+// party is connected.
//
-int WaitForRemote(int portNum)
+int WaitForRemote(ChannelEndPoint &socketAddress)
{
char hostLabel[DEFAULT_STRING_LENGTH] = { 0 };
+ char *socketUri = NULL;
int retryAccept = -1;
int proxyFD = -1;
int newFD = -1;
- //
- // Get IP address of host to be awaited.
- //
-
int acceptIPAddr = 0;
- if (*acceptHost != '\0')
+ if (socketAddress.isTCPSocket())
{
- acceptIPAddr = GetHostAddress(acceptHost);
- if (acceptIPAddr == 0)
+ //
+ // Get IP address of host to be awaited.
+ //
+
+ if (*acceptHost != '\0')
{
- #ifdef PANIC
- *logofs << "Loop: PANIC! Cannot accept connections from unknown host '"
- << acceptHost << "'.\n" << logofs_flush;
- #endif
+ acceptIPAddr = GetHostAddress(acceptHost);
- cerr << "Error" << ": Cannot accept connections from unknown host '"
- << acceptHost << "'.\n";
+ if (acceptIPAddr == 0)
+ {
+ #ifdef PANIC
+ *logofs << "Loop: PANIC! Cannot accept connections from unknown host '"
+ << acceptHost << "'.\n" << logofs_flush;
+ #endif
- goto WaitForRemoteError;
+ cerr << "Error" << ": Cannot accept connections from unknown host '"
+ << acceptHost << "'.\n";
+
+ goto WaitForRemoteError;
+ }
+ strcpy(hostLabel, "any host");
+ }
+ else
+ {
+ snprintf(hostLabel, sizeof(hostLabel), "'%s'", acceptHost);
+ }
+
+ if (loopbackBind)
+ {
+ long bindPort;
+ if (socketAddress.getTCPHostAndPort(NULL, &bindPort))
+ socketAddress.setSpec("localhost", bindPort);
}
- strcpy(hostLabel, "any host");
}
+ else if (socketAddress.isUnixSocket())
+ strcpy(hostLabel, "this host");
else
- {
- snprintf(hostLabel, sizeof(hostLabel), "'%s'", acceptHost);
- }
+ strcpy(hostLabel, "unknown origin (something went wrong!!!)");
+
- proxyFD = ListenConnectionTCP(((loopbackBind || (control->ProxyMode == proxy_server)) ? "localhost" : "*"),
- portNum, "NX");
+ proxyFD = ListenConnection(socketAddress, "NX");
+ socketAddress.getSpec(&socketUri);
#ifdef TEST
*logofs << "Loop: Waiting for connection from "
- << hostLabel << " on port '" << portNum
+ << hostLabel << " on socket '" << socketUri
<< "'.\n" << logofs_flush;
#endif
-
cerr << "Info" << ": Waiting for connection from "
- << hostLabel << " on port '" << portNum
+ << hostLabel << " on socket '" << socketUri
<< "'.\n";
+ free(socketUri);
//
// How many times to loop waiting for connections
@@ -6702,12 +6761,19 @@ int WaitForRemote(int portNum)
}
else if (result > 0 && FD_ISSET(proxyFD, &readSet))
{
- sockaddr_in newAddr;
-
- socklen_t addrLen = sizeof(sockaddr_in);
- newFD = accept(proxyFD, (sockaddr *) &newAddr, &addrLen);
+ sockaddr_in newAddrINET;
+ if (socketAddress.isUnixSocket())
+ {
+ socklen_t addrLen = sizeof(sockaddr_un);
+ newFD = accept(proxyFD, NULL, &addrLen);
+ }
+ else if (socketAddress.isTCPSocket())
+ {
+ socklen_t addrLen = sizeof(sockaddr_in);
+ newFD = accept(proxyFD, (sockaddr *) &newAddrINET, &addrLen);
+ }
if (newFD == -1)
{
#ifdef PANIC
@@ -6722,47 +6788,82 @@ int WaitForRemote(int portNum)
goto WaitForRemoteError;
}
- char *connectedHost = inet_ntoa(newAddr.sin_addr);
-
- if (*acceptHost == '\0' || (int) newAddr.sin_addr.s_addr == acceptIPAddr)
+ if (socketAddress.isUnixSocket())
{
- #ifdef TEST
-
- unsigned int connectedPort = ntohs(newAddr.sin_port);
- *logofs << "Loop: Accepted connection from '" << connectedHost
- << "' with port '" << connectedPort << "'.\n"
+ char * unixPath = NULL;
+ socketAddress.getUnixPath(&unixPath);
+ #ifdef TEST
+ *logofs << "Loop: Accepted connection from this host on Unix file socket '"
+ << unixPath << "'.\n"
<< logofs_flush;
#endif
- cerr << "Info" << ": Accepted connection from '"
- << connectedHost << "'.\n";
+ cerr << "Info" << ": Accepted connection from this host on Unix file socket '"
+ << unixPath << "'.\n";
+ free(unixPath);
break;
}
- else
+ else if (socketAddress.isTCPSocket())
{
- #ifdef PANIC
- *logofs << "Loop: WARNING! Refusing connection from '" << connectedHost
- << "' on port '" << portNum << "'.\n" << logofs_flush;
- #endif
- cerr << "Warning" << ": Refusing connection from '"
- << connectedHost << "'.\n";
- }
+ char *connectedHost = inet_ntoa(newAddrINET.sin_addr);
- //
- // Not the best way to elude a DOS attack...
- //
+ if (*acceptHost == '\0' || (int) newAddrINET.sin_addr.s_addr == acceptIPAddr)
+ {
+
+ #ifdef TEST
- sleep(5);
+ unsigned int connectedPort = ntohs(newAddrINET.sin_port);
+
+ *logofs << "Loop: Accepted connection from '" << connectedHost
+ << "' with port '" << connectedPort << "'.\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Info" << ": Accepted connection from '"
+ << connectedHost << "'.\n";
+
+ break;
+ }
+ else
+ {
+ #ifdef PANIC
+ *logofs << "Loop: WARNING! Refusing connection from '" << connectedHost
+ << "' on port '" << socketAddress.getTCPPort() << "'.\n" << logofs_flush;
+ #endif
+
+ cerr << "Warning" << ": Refusing connection from '"
+ << connectedHost << "'.\n";
+ }
+
+ //
+ // Not the best way to elude a DOS attack...
+ //
+
+ sleep(5);
+
+ close(newFD);
+
+ }
- close(newFD);
}
if (--retryAccept == 0)
{
- if (*acceptHost == '\0')
+ if (socketAddress.isUnixSocket())
+ {
+ #ifdef PANIC
+ *logofs << "Loop: PANIC! Connection via Unix file socket from this host "
+ << "could not be established.\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Connection via Unix file socket from this host "
+ << "could not be established.\n";
+ }
+ else if (*acceptHost == '\0')
{
#ifdef PANIC
*logofs << "Loop: PANIC! Connection with remote host "
@@ -6804,43 +6905,194 @@ WaitForRemoteError:
HandleCleanup();
}
-//
-// Connect to remote proxy. If successful
-// return FD of connection, else return -1.
-//
-
-int ConnectToRemote(const char *const hostName, int portNum)
+int PrepareProxyConnectionTCP(char** hostName, long int* portNum, int* timeout, int* proxyFD, int* reason)
{
- int proxyFD = -1;
- int remoteIPAddr = GetHostAddress(hostName);
+ if (!proxyFD)
+ {
+ #ifdef PANIC
+ *logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionTCP). "
+ << "'proxyFD' must not be a NULL pointer.\n" << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Implementation error (PrepareProxyConnectionTCP). "
+ << "'proxyFD' must not be a NULL pointer.\n";
+
+ return -1;
+ }
+
+ if (!reason)
+ {
+ #ifdef PANIC
+ *logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionTCP). "
+ << "'reason' must not be a NULL pointer.\n" << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Implementation error (PrepareProxyConnectionTCP). "
+ << "'reason' must not be a NULL pointer.\n";
+
+ return -1;
+ }
+ int remoteIPAddr = GetHostAddress(*hostName);
if (remoteIPAddr == 0)
{
#ifdef PANIC
*logofs << "Loop: PANIC! Unknown remote host '"
- << hostName << "'.\n" << logofs_flush;
+ << *hostName << "'.\n" << logofs_flush;
#endif
-
- cerr << "Error" << ": Unknown remote host '"
- << hostName << "'.\n";
+ cerr << "Error" << ": Unknown remote host '"
+ << *hostName << "'.\n";
HandleCleanup();
}
#ifdef TEST
*logofs << "Loop: Connecting to remote host '"
- << hostName << ":" << portNum << "'.\n"
+ << *hostName << ":" << *portNum << "'.\n"
<< logofs_flush;
#endif
cerr << "Info" << ": Connecting to remote host '"
- << hostName << ":" << portNum << "'.\n"
+ << *hostName << ":" << *portNum << "'.\n"
<< logofs_flush;
+ *proxyFD = -1;
+ *reason = -1;
+
+ sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(*portNum);
+ addr.sin_addr.s_addr = remoteIPAddr;
+
+ *proxyFD = socket(AF_INET, SOCK_STREAM, PF_UNSPEC);
+ *reason = EGET();
+
+ if (*proxyFD == -1)
+ {
+ #ifdef PANIC
+ *logofs << "Loop: PANIC! Call to socket failed. "
+ << "Error is " << *reason << " '" << ESTR()
+ << "'.\n" << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Call to socket failed. "
+ << "Error is " << *reason << " '" << ESTR()
+ << "'.\n";
+ return -1;
+
+ }
+ else if (SetReuseAddress(*proxyFD) < 0)
+ {
+ return -1;
+ }
+
+ //
+ // Ensure operation is timed out
+ // if there is a network problem.
+ //
+
+ if (timeout)
+ SetTimer(*timeout);
+ else
+ SetTimer(20000);
+
+ int result = connect(*proxyFD, (sockaddr *) &addr, sizeof(sockaddr_in));
+
+ *reason = EGET();
+
+ ResetTimer();
+
+ return result;
+
+}
+
+int PrepareProxyConnectionUnix(char** path, int* timeout, int* proxyFD, int* reason)
+{
+
+ if (!proxyFD)
+ {
+ #ifdef PANIC
+ *logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionUnix). "
+ << "proxyFD must not be a NULL pointer.\n" << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Implementation error (PrepareProxyConnectionUnix). "
+ << "proxyFD must not be a NULL pointer.\n";
+
+ return -1;
+ }
+
+ if (!reason)
+ {
+ #ifdef PANIC
+ *logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionUnix). "
+ << "'reason' must not be a NULL pointer.\n" << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Implementation error (PrepareProxyConnectionUnix). "
+ << "'reason' must not be a NULL pointer.\n";
+
+ return -1;
+ }
+
+ /* FIXME: Add socket file existence and permission checks */
+
+ *proxyFD = -1;
+ *reason = -1;
+
+ sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, *path, 108 - 1);
+
+ *proxyFD = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC);
+ *reason = EGET();
+
+ if (*proxyFD == -1)
+ {
+ #ifdef PANIC
+ *logofs << "Loop: PANIC! Call to socket failed. "
+ << "Error is " << *reason << " '" << ESTR()
+ << "'.\n" << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Call to socket failed. "
+ << "Error is " << *reason << " '" << ESTR()
+ << "'.\n";
+
+ return -1;
+ }
+
+ //
+ // Ensure operation is timed out
+ // if there is a network problem.
+ //
+
+ if (timeout)
+ SetTimer(*timeout);
+ else
+ SetTimer(20000);
+
+ int result = connect(*proxyFD, (sockaddr *) &addr, sizeof(sockaddr_un));
+
+ *reason = EGET();
+
+ ResetTimer();
+
+ return result;
+}
+
+//
+// Connect to remote proxy. If successful
+// return FD of connection, else return -1.
+//
+
+int ConnectToRemote(ChannelEndPoint &socketAddress)
+{
+
//
// How many times we retry to connect to remote
- // host in case of failure?
+ // host / Unix domain socket in case of failure?
//
int retryConnect = control -> OptionProxyRetryConnect;
@@ -6858,39 +7110,16 @@ int ConnectToRemote(const char *const hostName, int portNum)
T_timestamp lastRetry = getNewTimestamp();
- sockaddr_in addr;
+ int result = -1;
+ int reason = -1;
+ int proxyFD = -1;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(portNum);
- addr.sin_addr.s_addr = remoteIPAddr;
+ char *hostName = NULL;
+ long int portNum = -1;
+ char *unixPath = NULL;
for (;;)
{
- proxyFD = socket(AF_INET, SOCK_STREAM, PF_UNSPEC);
-
- if (proxyFD == -1)
- {
- #ifdef PANIC
- *logofs << "Loop: PANIC! Call to socket failed. "
- << "Error is " << EGET() << " '" << ESTR()
- << "'.\n" << logofs_flush;
- #endif
-
- cerr << "Error" << ": Call to socket failed. "
- << "Error is " << EGET() << " '" << ESTR()
- << "'.\n";
-
- goto ConnectToRemoteError;
- }
- else if (SetReuseAddress(proxyFD) < 0)
- {
- goto ConnectToRemoteError;
- }
-
- //
- // Ensure operation is timed out
- // if there is a network problem.
- //
#ifdef DEBUG
*logofs << "Loop: Timer set to " << connectTimeout / 1000
@@ -6899,13 +7128,10 @@ int ConnectToRemote(const char *const hostName, int portNum)
<< "'.\n" << logofs_flush;
#endif
- SetTimer(connectTimeout);
-
- int result = connect(proxyFD, (sockaddr *) &addr, sizeof(sockaddr_in));
-
- int reason = EGET();
-
- ResetTimer();
+ if (socketAddress.getUnixPath(&unixPath))
+ result = PrepareProxyConnectionUnix(&unixPath, &connectTimeout, &proxyFD, &reason);
+ else if (socketAddress.getTCPHostAndPort(&hostName, &portNum))
+ result = PrepareProxyConnectionTCP(&hostName, &portNum, &connectTimeout, &proxyFD, &reason);
if (result < 0)
{
@@ -6919,24 +7145,40 @@ int ConnectToRemote(const char *const hostName, int portNum)
{
ESET(reason);
- #ifdef PANIC
- *logofs << "Loop: PANIC! Connection to '" << hostName
- << ":" << portNum << "' failed. Error is "
- << EGET() << " '" << ESTR() << "'.\n"
- << logofs_flush;
- #endif
+ if (socketAddress.isUnixSocket())
+ {
+ #ifdef PANIC
+ *logofs << "Loop: PANIC! Connection to Unix file socket '"
+ << unixPath << "' failed. Error is "
+ << EGET() << " '" << ESTR() << "'.\n"
+ << logofs_flush;
+ #endif
- cerr << "Error" << ": Connection to '" << hostName
- << ":" << portNum << "' failed. Error is "
- << EGET() << " '" << ESTR() << "'.\n";
+ cerr << "Error" << ": Connection to Unix file socket '"
+ << unixPath << "' failed. Error is "
+ << EGET() << " '" << ESTR() << "'.\n";
+ }
+ else
+ {
+ #ifdef PANIC
+ *logofs << "Loop: PANIC! Connection to '" << hostName
+ << ":" << portNum << "' failed. Error is "
+ << EGET() << " '" << ESTR() << "'.\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Connection to '" << hostName
+ << ":" << portNum << "' failed. Error is "
+ << EGET() << " '" << ESTR() << "'.\n";
+ }
goto ConnectToRemoteError;
}
else
{
#ifdef TEST
- *logofs << "Loop: Sleeping " << retryTimeout
- << " Ms before retrying.\n"
+ *logofs << "Loop: Sleeping " << retryTimeout
+ << " ms before retrying.\n"
<< logofs_flush;
#endif
@@ -7005,10 +7247,20 @@ int ConnectToRemote(const char *const hostName, int portNum)
ESET(reason);
#ifdef TEST
- *logofs << "Loop: Connection to '" << hostName
- << ":" << portNum << "' failed with error '"
- << ESTR() << "'. Retrying.\n"
- << logofs_flush;
+ if (unixPath[0] != '\0' )
+ {
+ *logofs << "Loop: Connection to Unix socket file '"
+ << unixPath << "' failed with error '"
+ << ESTR() << "'. Retrying.\n"
+ << logofs_flush;
+ }
+ else
+ {
+ *logofs << "Loop: Connection to '" << hostName
+ << ":" << portNum << "' failed with error '"
+ << ESTR() << "'. Retrying.\n"
+ << logofs_flush;
+ }
#endif
}
else
@@ -8234,6 +8486,9 @@ int ParseEnvironmentOptions(const char *env, int force)
name = strtok(nextOpts, "=");
+ char connectHost[DEFAULT_STRING_LENGTH] = { 0 };
+ long connectPort = -1;
+
while (name)
{
value = strtok(NULL, ",");
@@ -8254,6 +8509,7 @@ int ParseEnvironmentOptions(const char *env, int force)
}
else if (strcasecmp(name, "link") == 0)
{
+
if (control -> ProxyMode == proxy_server)
{
PrintOptionIgnored("local", name, value);
@@ -8315,26 +8571,29 @@ int ParseEnvironmentOptions(const char *env, int force)
}
else if (strcasecmp(name, "listen") == 0)
{
- if (*connectHost != '\0')
+ char *socketUri = NULL;
+ if (connectSocket.getSpec(&socketUri))
{
#ifdef PANIC
*logofs << "Loop: PANIC! Can't handle 'listen' and 'connect' parameters "
<< "at the same time.\n" << logofs_flush;
*logofs << "Loop: PANIC! Refusing 'listen' parameter with 'connect' being '"
- << connectHost << "'.\n" << logofs_flush;
+ << socketUri << "'.\n" << logofs_flush;
#endif
cerr << "Error" << ": Can't handle 'listen' and 'connect' parameters "
<< "at the same time.\n";
cerr << "Error" << ": Refusing 'listen' parameter with 'connect' being '"
- << connectHost << "'.\n";
+ << socketUri << "'.\n";
+ free(socketUri);
return -1;
}
- listenPort = ValidateArg("local", name, value);
+ SetAndValidateChannelEndPointArg("local", name, value, listenSocket);
+
}
else if (strcasecmp(name, "loopback") == 0)
{
@@ -8342,22 +8601,24 @@ int ParseEnvironmentOptions(const char *env, int force)
}
else if (strcasecmp(name, "accept") == 0)
{
- if (*connectHost != '\0')
+ char *socketUri = NULL;
+ if (connectSocket.getSpec(&socketUri))
{
#ifdef PANIC
*logofs << "Loop: PANIC! Can't handle 'accept' and 'connect' parameters "
<< "at the same time.\n" << logofs_flush;
*logofs << "Loop: PANIC! Refusing 'accept' parameter with 'connect' being '"
- << connectHost << "'.\n" << logofs_flush;
+ << socketUri << "'.\n" << logofs_flush;
#endif
cerr << "Error" << ": Can't handle 'accept' and 'connect' parameters "
<< "at the same time.\n";
cerr << "Error" << ": Refusing 'accept' parameter with 'connect' being '"
- << connectHost << "'.\n";
+ << socketUri << "'.\n";
+ free(socketUri);
return -1;
}
@@ -8383,8 +8644,12 @@ int ParseEnvironmentOptions(const char *env, int force)
return -1;
}
-
- strncpy(connectHost, value, DEFAULT_STRING_LENGTH - 1);
+ if ((strncmp(value, "tcp:", 4) == 0) || (strncmp(value, "unix:", 5) == 0))
+ SetAndValidateChannelEndPointArg("local", name, value, connectSocket);
+ else
+ // if the "connect" parameter does not start with "unix:" or "tcp:" assume
+ // old parameter usage style (providing hostname string only).
+ strcpy(connectHost, value);
}
else if (strcasecmp(name, "port") == 0)
{
@@ -8842,6 +9107,17 @@ int ParseEnvironmentOptions(const char *env, int force)
} // End of while (name) ...
+ // Assemble the connectSocket channel end point if parameter values have been old-school...
+ if (connectSocket.disabled() && (connectHost[0] != '\0') && (proxyPort > 0 || connectPort > 0))
+ {
+ if (connectPort < 0)
+ connectPort = proxyPort + DEFAULT_NX_PROXY_PORT_OFFSET;
+
+ char tcpHostAndPort[DEFAULT_STRING_LENGTH] = { 0 };
+ sprintf(tcpHostAndPort, "tcp:%s:%ld", connectHost, connectPort);
+ SetAndValidateChannelEndPointArg("local", name, tcpHostAndPort, connectSocket);
+ }
+
#ifdef TEST
*logofs << "Loop: Completed parsing of string '"
<< env << "'.\n" << logofs_flush;
@@ -9082,16 +9358,21 @@ int ParseCommandLineOptions(int argc, const char **argv)
// command line at the connecting side.
//
- if (ParseHostOption(nextArg, connectHost, connectPort) > 0)
- {
- //
- // Assume port is at a proxied display offset.
- //
+ char *cHost;
+ long cPort;
- proxyPort = connectPort;
+ if (connectSocket.getTCPHostAndPort(&cHost, &cPort) && (ParseHostOption(nextArg, cHost, cPort) > 0))
+ {
+ //
+ // Assume port is at a proxied display offset.
+ //
- connectPort += DEFAULT_NX_PROXY_PORT_OFFSET;
- }
+ proxyPort = cPort;
+
+ cPort += DEFAULT_NX_PROXY_PORT_OFFSET;
+ connectSocket.setSpec(cHost, cPort);
+
+ }
else if (ParseEnvironmentOptions(nextArg, 1) < 0)
{
return -1;
@@ -13195,7 +13476,7 @@ int ParseBitrateOption(const char *opt)
return 1;
}
-int ParseHostOption(const char *opt, char *host, int &port)
+int ParseHostOption(const char *opt, char *host, long &port)
{
#ifdef TEST
*logofs << "Loop: Trying to parse options string '" << opt