Bug 572570 - backed out changeset 90ade0c197ed due to linux m0 oranges

This commit is contained in:
Jonathan Griffin 2010-07-26 16:01:06 -07:00
parent e1a1e214a6
commit 889921576e
3 changed files with 90 additions and 120 deletions

View File

@ -60,6 +60,7 @@ _DEFAULT_WEB_SERVER = "127.0.0.1"
_DEFAULT_HTTP_PORT = 8888 _DEFAULT_HTTP_PORT = 8888
_DEFAULT_SSL_PORT = 4443 _DEFAULT_SSL_PORT = 4443
_DEFAULT_WEBSOCKET_PORT = 9988 _DEFAULT_WEBSOCKET_PORT = 9988
_DEFAULT_WEBSOCKET_PROXY_PORT = 7777
#expand _DIST_BIN = __XPC_BIN_PATH__ #expand _DIST_BIN = __XPC_BIN_PATH__
#expand _IS_WIN32 = len("__WIN32__") != 0 #expand _IS_WIN32 = len("__WIN32__") != 0
@ -154,6 +155,7 @@ class Automation(object):
DEFAULT_HTTP_PORT = _DEFAULT_HTTP_PORT DEFAULT_HTTP_PORT = _DEFAULT_HTTP_PORT
DEFAULT_SSL_PORT = _DEFAULT_SSL_PORT DEFAULT_SSL_PORT = _DEFAULT_SSL_PORT
DEFAULT_WEBSOCKET_PORT = _DEFAULT_WEBSOCKET_PORT DEFAULT_WEBSOCKET_PORT = _DEFAULT_WEBSOCKET_PORT
DEFAULT_WEBSOCKET_PROXY_PORT = _DEFAULT_WEBSOCKET_PROXY_PORT
def __init__(self): def __init__(self):
self.log = _log self.log = _log
@ -163,11 +165,13 @@ class Automation(object):
webServer = _DEFAULT_WEB_SERVER, webServer = _DEFAULT_WEB_SERVER,
httpPort = _DEFAULT_HTTP_PORT, httpPort = _DEFAULT_HTTP_PORT,
sslPort = _DEFAULT_SSL_PORT, sslPort = _DEFAULT_SSL_PORT,
webSocketPort = _DEFAULT_WEBSOCKET_PORT): webSocketPort = _DEFAULT_WEBSOCKET_PORT,
webSocketProxyPort = _DEFAULT_WEBSOCKET_PROXY_PORT):
self.webServer = webServer self.webServer = webServer
self.httpPort = httpPort self.httpPort = httpPort
self.sslPort = sslPort self.sslPort = sslPort
self.webSocketPort = webSocketPort self.webSocketPort = webSocketPort
self.webSocketProxyPort = webSocketProxyPort
@property @property
def __all__(self): def __all__(self):
@ -402,13 +406,16 @@ function FindProxyForURL(url, host)
return 'DIRECT'; return 'DIRECT';
if (isHttp) if (isHttp)
return 'PROXY %(remote)s:%(httpport)s'; return 'PROXY %(remote)s:%(httpport)s';
if (isHttps || isWebSocket) if (isHttps)
return 'PROXY %(remote)s:%(sslport)s'; return 'PROXY %(remote)s:%(sslport)s';
if (isWebSocket)
return 'PROXY %(remote)s:%(websocketproxyport)s';
return 'DIRECT'; return 'DIRECT';
}""" % { "origins": origins, }""" % { "origins": origins,
"remote": self.webServer, "remote": self.webServer,
"httpport":self.httpPort, "httpport":self.httpPort,
"sslport": self.sslPort } "sslport": self.sslPort,
"websocketproxyport": self.webSocketProxyPort }
pacURL = "".join(pacURL.splitlines()) pacURL = "".join(pacURL.splitlines())
part += """ part += """
@ -455,7 +462,8 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
sslTunnelConfig.write("httpproxy:1\n") sslTunnelConfig.write("httpproxy:1\n")
sslTunnelConfig.write("certdbdir:%s\n" % certPath) sslTunnelConfig.write("certdbdir:%s\n" % certPath)
sslTunnelConfig.write("forward:127.0.0.1:%s\n" % self.httpPort) sslTunnelConfig.write("forward:127.0.0.1:%s\n" % self.httpPort)
sslTunnelConfig.write("websocketserver:%s:%s\n" % (self.webServer, self.webSocketPort)) sslTunnelConfig.write("proxy:%s:%s:%s\n" %
(self.webSocketProxyPort, self.webServer, self.webSocketPort))
sslTunnelConfig.write("listen:*:%s:pgo server certificate\n" % self.sslPort) sslTunnelConfig.write("listen:*:%s:pgo server certificate\n" % self.sslPort)
# Configure automatic certificate and bind custom certificates, client authentication # Configure automatic certificate and bind custom certificates, client authentication

View File

@ -267,6 +267,7 @@ See <http://mochikit.com/doc/html/MochiKit/Logging.html> for details on the logg
options.httpPort = self._automation.DEFAULT_HTTP_PORT options.httpPort = self._automation.DEFAULT_HTTP_PORT
options.sslPort = self._automation.DEFAULT_SSL_PORT options.sslPort = self._automation.DEFAULT_SSL_PORT
options.webSocketPort = self._automation.DEFAULT_WEBSOCKET_PORT options.webSocketPort = self._automation.DEFAULT_WEBSOCKET_PORT
options.webSocketProxyPort = self._automation.DEFAULT_WEBSOCKET_PROXY_PORT
if options.vmwareRecording: if options.vmwareRecording:
if not self._automation.IS_WIN32: if not self._automation.IS_WIN32:
@ -723,7 +724,8 @@ def main():
automation.setServerInfo(options.webServer, automation.setServerInfo(options.webServer,
options.httpPort, options.httpPort,
options.sslPort, options.sslPort,
options.webSocketPort) options.webSocketPort,
options.webSocketProxyPort)
sys.exit(mochitest.runTests(options)) sys.exit(mochitest.runTests(options))
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -121,29 +121,26 @@ typedef struct {
string cert_nickname; string cert_nickname;
PLHashTable* host_cert_table; PLHashTable* host_cert_table;
PLHashTable* host_clientauth_table; PLHashTable* host_clientauth_table;
// If not empty, and this server is using HTTP CONNECT, connections
// will be proxied to this address.
PRNetAddr remote_addr;
// True if no SSL should be used for this server's connections.
bool http_proxy_only;
// The original host in the Host: header for the initial connection is
// stored here, for proxied connections.
string original_host;
} server_info_t; } server_info_t;
typedef struct { typedef struct {
PRFileDesc* client_sock; PRFileDesc* client_sock;
PRNetAddr client_addr; PRNetAddr client_addr;
server_info_t* server_info; server_info_t* server_info;
// the original host in the Host: header for this connection is
// stored here, for proxied connections
string original_host;
// true if no SSL should be used for this connection
bool http_proxy_only;
// true if this connection is for a WebSocket
bool iswebsocket;
} connection_info_t; } connection_info_t;
typedef struct {
string fullHost;
bool matched;
} server_match_t;
const PRInt32 BUF_SIZE = 16384; const PRInt32 BUF_SIZE = 16384;
const PRInt32 BUF_MARGIN = 1024; const PRInt32 BUF_MARGIN = 1024;
const PRInt32 BUF_TOTAL = BUF_SIZE + BUF_MARGIN; const PRInt32 BUF_TOTAL = BUF_SIZE + BUF_MARGIN;
const char HEADER_HOST[] = "Host:";
struct relayBuffer struct relayBuffer
{ {
@ -220,7 +217,6 @@ const PRUint32 DEFAULT_STACKSIZE = (512 * 1024);
string nssconfigdir; string nssconfigdir;
vector<server_info_t> servers; vector<server_info_t> servers;
PRNetAddr remote_addr; PRNetAddr remote_addr;
PRNetAddr websocket_server;
PRThreadPool* threads = NULL; PRThreadPool* threads = NULL;
PRLock* shutdown_lock = NULL; PRLock* shutdown_lock = NULL;
PRCondVar* shutdown_condvar = NULL; PRCondVar* shutdown_condvar = NULL;
@ -241,14 +237,6 @@ PR_CALLBACK PRIntn ClientAuthValueComparator(const void *v1, const void *v2)
return -1; return -1;
} }
static PRIntn match_hostname(PLHashEntry *he, PRIntn index, void* arg)
{
server_match_t *match = (server_match_t*)arg;
if (match->fullHost.find((char*)he->key) != string::npos)
match->matched = true;
return HT_ENUMERATE_NEXT;
}
/* /*
* Signal the main thread that the application should shut down. * Signal the main thread that the application should shut down.
*/ */
@ -366,15 +354,15 @@ bool ConfigureSSLServerSocket(PRFileDesc* socket, server_info_t* si, string &cer
* This function examines the buffer for a S5ec-WebSocket-Location: field, * This function examines the buffer for a S5ec-WebSocket-Location: field,
* and if it's present, it replaces the hostname in that field with the * and if it's present, it replaces the hostname in that field with the
* value in the server's original_host field. This function works * value in the server's original_host field. This function works
* in the reverse direction as AdjustWebSocketHost(), replacing the real * in the reverse direction as AdjustHost(), replacing the real hostname
* hostname of a response with the potentially fake hostname that is expected * of a response with the potentially fake hostname that is expected
* by the browser (e.g., mochi.test). * by the browser (e.g., mochi.test).
* *
* @return true if the header was adjusted successfully, or not found, false * @return true if the header was adjusted successfully, or not found, false
* if the header is present but the url is not, which should indicate * if the header is present but the url is not, which should indicate
* that more data needs to be read from the socket * that more data needs to be read from the socket
*/ */
bool AdjustWebSocketLocation(relayBuffer& buffer, connection_info_t *ci) bool AdjustWebSocketLocation(relayBuffer& buffer, server_info_t *si)
{ {
assert(buffer.margin()); assert(buffer.margin());
buffer.buffertail[1] = '\0'; buffer.buffertail[1] = '\0';
@ -394,16 +382,16 @@ bool AdjustWebSocketLocation(relayBuffer& buffer, connection_info_t *ci)
char *crlf = strstr(wsloc, "\r\n"); char *crlf = strstr(wsloc, "\r\n");
if (!crlf) if (!crlf)
return false; return false;
if (ci->original_host.empty()) if (si->original_host.empty())
return true; return true;
int diff = ci->original_host.length() - (wslocend-wsloc); int diff = si->original_host.length() - (wslocend-wsloc);
if (diff > 0) if (diff > 0)
assert(size_t(diff) <= buffer.margin()); assert(size_t(diff) <= buffer.margin());
memmove(wslocend + diff, wslocend, buffer.buffertail - wsloc - diff); memmove(wslocend + diff, wslocend, buffer.buffertail - wsloc - diff);
buffer.buffertail += diff; buffer.buffertail += diff;
memcpy(wsloc, ci->original_host.c_str(), ci->original_host.length()); memcpy(wsloc, si->original_host.c_str(), si->original_host.length());
return true; return true;
} }
@ -415,13 +403,10 @@ bool AdjustWebSocketLocation(relayBuffer& buffer, connection_info_t *ci)
* replaced with the host that the destination server is actually running * replaced with the host that the destination server is actually running
* on. * on.
*/ */
bool AdjustWebSocketHost(relayBuffer& buffer, connection_info_t *ci) bool AdjustHost(relayBuffer& buffer, server_info_t *si)
{ {
const char HEADER_UPGRADE[] = "Upgrade:"; if (!si->remote_addr.inet.port)
const char HEADER_HOST[] = "Host:"; return false;
PRNetAddr inet_addr = (websocket_server.inet.port ? websocket_server :
remote_addr);
assert(buffer.margin()); assert(buffer.margin());
@ -429,16 +414,6 @@ bool AdjustWebSocketHost(relayBuffer& buffer, connection_info_t *ci)
// space left because we preserve a margin. // space left because we preserve a margin.
buffer.buffertail[1] = '\0'; buffer.buffertail[1] = '\0';
// Verify this is a WebSocket header.
char* h1 = strstr(buffer.bufferhead, HEADER_UPGRADE);
if (!h1)
return false;
h1 += strlen(HEADER_UPGRADE);
h1 += strspn(h1, " \t");
char* h2 = strstr(h1, "WebSocket\r\n");
if (!h2)
return false;
char* host = strstr(buffer.bufferhead, HEADER_HOST); char* host = strstr(buffer.bufferhead, HEADER_HOST);
if (!host) if (!host)
return false; return false;
@ -452,12 +427,12 @@ bool AdjustWebSocketHost(relayBuffer& buffer, connection_info_t *ci)
// Save the original host, so we can use it later on responses from the // Save the original host, so we can use it later on responses from the
// server. // server.
ci->original_host.assign(host, endhost-host); si->original_host.assign(host, endhost-host);
char newhost[40]; char newhost[40];
PR_NetAddrToString(&inet_addr, newhost, sizeof(newhost)); PR_NetAddrToString(&si->remote_addr, newhost, sizeof(newhost));
assert(strlen(newhost) < sizeof(newhost) - 7); assert(strlen(newhost) < sizeof(newhost) - 7);
sprintf(newhost, "%s:%d", newhost, PR_ntohs(inet_addr.inet.port)); sprintf(newhost, "%s:%d", newhost, PR_ntohs(si->remote_addr.inet.port));
int diff = strlen(newhost) - (endhost-host); int diff = strlen(newhost) - (endhost-host);
if (diff > 0) if (diff > 0)
@ -557,7 +532,7 @@ void HandleConnection(void* data)
if (!do_http_proxy) if (!do_http_proxy)
{ {
if (!ci->http_proxy_only && if (!ci->server_info->http_proxy_only &&
!ConfigureSSLServerSocket(ci->client_sock, ci->server_info, certificateToUse, caNone)) !ConfigureSSLServerSocket(ci->client_sock, ci->server_info, certificateToUse, caNone))
client_error = true; client_error = true;
else if (!ConnectSocket(other_sock, &remote_addr, connect_timeout)) else if (!ConnectSocket(other_sock, &remote_addr, connect_timeout))
@ -677,33 +652,12 @@ void HandleConnection(void* data)
if (!connect_accepted && ReadConnectRequest(ci->server_info, buffers[s], if (!connect_accepted && ReadConnectRequest(ci->server_info, buffers[s],
&response, certificateToUse, &clientAuth, fullHost)) &response, certificateToUse, &clientAuth, fullHost))
{ {
// Mark this as a proxy-only connection (no SSL) if the CONNECT
// request didn't come for port 443 or from any of the server's
// cert or clientauth hostnames.
if (fullHost.find(":443") == string::npos)
{
server_match_t match;
match.fullHost = fullHost;
match.matched = false;
PL_HashTableEnumerateEntries(ci->server_info->host_cert_table,
match_hostname,
&match);
PL_HashTableEnumerateEntries(ci->server_info->host_clientauth_table,
match_hostname,
&match);
ci->http_proxy_only = !match.matched;
}
else
{
ci->http_proxy_only = false;
}
// Clean the request as it would be read // Clean the request as it would be read
buffers[s].bufferhead = buffers[s].buffertail = buffers[s].buffer; buffers[s].bufferhead = buffers[s].buffertail = buffers[s].buffer;
in_flags |= PR_POLL_WRITE; in_flags |= PR_POLL_WRITE;
connect_accepted = true; connect_accepted = true;
// Store response to the opposite buffer // Store response to the oposite buffer
if (response != 200) if (response != 200)
{ {
printf(" could not read the connect request, closing connection with %d", response); printf(" could not read the connect request, closing connection with %d", response);
@ -716,6 +670,16 @@ void HandleConnection(void* data)
strcpy(buffers[s2].buffer, "HTTP/1.1 200 Connected\r\nConnection: keep-alive\r\n\r\n"); strcpy(buffers[s2].buffer, "HTTP/1.1 200 Connected\r\nConnection: keep-alive\r\n\r\n");
buffers[s2].buffertail = buffers[s2].buffer + strlen(buffers[s2].buffer); buffers[s2].buffertail = buffers[s2].buffer + strlen(buffers[s2].buffer);
PRNetAddr* addr = &remote_addr;
if (ci->server_info->remote_addr.inet.port > 0)
addr = &ci->server_info->remote_addr;
if (!ConnectSocket(other_sock, addr, connect_timeout))
{
printf(" could not open connection to the real server\n");
client_error = true;
break;
}
printf(" accepted CONNECT request, connected to the server, sending OK to the client\n"); printf(" accepted CONNECT request, connected to the server, sending OK to the client\n");
// Send the response to the client socket // Send the response to the client socket
break; break;
@ -732,31 +696,14 @@ void HandleConnection(void* data)
{ {
if (s == 0 && expect_request_start) if (s == 0 && expect_request_start)
{ {
if (!strstr(buffers[s].bufferhead, "\r\n\r\n")) if (ci->server_info->http_proxy_only)
{ expect_request_start = !AdjustHost(buffers[s], ci->server_info);
// We haven't received the complete header yet, so wait.
continue;
}
else else
{ expect_request_start = !AdjustRequestURI(buffers[s], &fullHost);
ci->iswebsocket = AdjustWebSocketHost(buffers[s], ci);
expect_request_start = !(ci->iswebsocket ||
AdjustRequestURI(buffers[s], &fullHost));
PRNetAddr* addr = &remote_addr;
if (ci->iswebsocket && websocket_server.inet.port)
addr = &websocket_server;
if (!ConnectSocket(other_sock, addr, connect_timeout))
{
printf(" could not open connection to the real server\n");
client_error = true;
break;
}
printf("\n connected to remote server\n");
}
} }
else if (s == 1 && ci->iswebsocket) else
{ {
if (!AdjustWebSocketLocation(buffers[s], ci)) if (!AdjustWebSocketLocation(buffers[s], ci->server_info))
continue; continue;
} }
@ -770,7 +717,7 @@ void HandleConnection(void* data)
if (out_flags & PR_POLL_WRITE) if (out_flags & PR_POLL_WRITE)
{ {
printf(" :writing"); printf(" :writting");
PRInt32 bytesWrite = PR_Send(sockets[s].fd, buffers[s2].bufferhead, PRInt32 bytesWrite = PR_Send(sockets[s].fd, buffers[s2].bufferhead,
buffers[s2].present(), 0, PR_INTERVAL_NO_TIMEOUT); buffers[s2].present(), 0, PR_INTERVAL_NO_TIMEOUT);
@ -806,7 +753,7 @@ void HandleConnection(void* data)
printf(" proxy response sent to the client"); printf(" proxy response sent to the client");
// Proxy response has just been writen, update to ssl // Proxy response has just been writen, update to ssl
ssl_updated = true; ssl_updated = true;
if (!ci->http_proxy_only && if (!ci->server_info->http_proxy_only &&
!ConfigureSSLServerSocket(ci->client_sock, ci->server_info, certificateToUse, clientAuth)) !ConfigureSSLServerSocket(ci->client_sock, ci->server_info, certificateToUse, clientAuth))
{ {
printf(" but failed to config server socket\n"); printf(" but failed to config server socket\n");
@ -945,23 +892,6 @@ int processConfigLine(char* configLine)
return 0; return 0;
} }
if (!strcmp(keyword, "websocketserver"))
{
char* ipstring = strtok2(_caret, ":", &_caret);
if (PR_StringToNetAddr(ipstring, &websocket_server) != PR_SUCCESS) {
fprintf(stderr, "Invalid IP address in proxy config: %s\n", ipstring);
return 1;
}
char* remoteport = strtok2(_caret, ":", &_caret);
int port = atoi(remoteport);
if (port <= 0) {
fprintf(stderr, "Invalid remote port in proxy config: %s\n", remoteport);
return 1;
}
websocket_server.inet.port = PR_htons(port);
return 0;
}
// Configure the forward address of the target server // Configure the forward address of the target server
if (!strcmp(keyword, "forward")) if (!strcmp(keyword, "forward"))
{ {
@ -981,6 +911,35 @@ int processConfigLine(char* configLine)
return 0; return 0;
} }
if (!strcmp(keyword, "proxy"))
{
server_info_t server;
server.host_cert_table = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareStrings, NULL, NULL);
server.host_clientauth_table = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, ClientAuthValueComparator, NULL, NULL);
server.http_proxy_only = true;
char* listenport = strtok2(_caret, ":", &_caret);
server.listen_port = atoi(listenport);
if (server.listen_port <= 0) {
fprintf(stderr, "Invalid listen port in proxy config: %s\n", listenport);
return 1;
}
char* ipstring = strtok2(_caret, ":", &_caret);
if (PR_StringToNetAddr(ipstring, &server.remote_addr) != PR_SUCCESS) {
fprintf(stderr, "Invalid IP address in proxy config: %s\n", ipstring);
return 1;
}
char* remoteport = strtok2(_caret, ":", &_caret);
int port = atoi(remoteport);
if (port <= 0) {
fprintf(stderr, "Invalid remote port in proxy config: %s\n", remoteport);
return 1;
}
server.remote_addr.inet.port = PR_htons(port);
servers.push_back(server);
return 0;
}
// Configure all listen sockets and port+certificate bindings // Configure all listen sockets and port+certificate bindings
if (!strcmp(keyword, "listen")) if (!strcmp(keyword, "listen"))
{ {
@ -1020,8 +979,10 @@ int processConfigLine(char* configLine)
else else
{ {
server_info_t server; server_info_t server;
memset(&server.remote_addr, 0, sizeof(PRNetAddr));
server.cert_nickname = certnick; server.cert_nickname = certnick;
server.listen_port = port; server.listen_port = port;
server.http_proxy_only = false;
server.host_cert_table = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareStrings, NULL, NULL); server.host_cert_table = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareStrings, NULL, NULL);
if (!server.host_cert_table) if (!server.host_cert_table)
{ {
@ -1175,8 +1136,6 @@ int main(int argc, char** argv)
else else
configFilePath = argv[1]; configFilePath = argv[1];
memset(&websocket_server, 0, sizeof(PRNetAddr));
if (parseConfigFile(configFilePath)) { if (parseConfigFile(configFilePath)) {
fprintf(stderr, "Error: config file \"%s\" missing or formating incorrect\n" fprintf(stderr, "Error: config file \"%s\" missing or formating incorrect\n"
"Specify path to the config file as parameter to ssltunnel or \n" "Specify path to the config file as parameter to ssltunnel or \n"
@ -1204,9 +1163,10 @@ int main(int argc, char** argv)
" # specified. You also have to specify the tunnel listen port.\n" " # specified. You also have to specify the tunnel listen port.\n"
" clientauth:requesting-client-cert.host.com:443:4443:request\n" " clientauth:requesting-client-cert.host.com:443:4443:request\n"
" clientauth:requiring-client-cert.host.com:443:4443:require\n" " clientauth:requiring-client-cert.host.com:443:4443:require\n"
" # Proxy WebSocket traffic to the server at 127.0.0.1:9999,\n" " # Act as a simple proxy for incoming connections on port 7777,\n"
" # instead of the server specified in the 'forward' option.\n" " # tunneling them to the server at 127.0.0.1:9999. Not affected\n"
" websocketserver:127.0.0.1:9999\n", " # by the 'forward' option.\n"
" proxy:7777:127.0.0.1:9999\n",
configFilePath); configFilePath);
return 1; return 1;
} }