Skip to content
This repository has been archived by the owner on Jun 24, 2023. It is now read-only.

Commit

Permalink
Issue #37: support websockets
Browse files Browse the repository at this point in the history
Implemented functions for WebSockets and Secure WebSockets support. The process
for treating HTTP requests in core.c has then been changed:

1. for every new request with a CONNECT,  create_http_socket() will peak into
the next request to determine if the next message contains binary (i.e
encrypted) content. If so, proceed with ssl/tls interception routine. This is
because WebSocket RFC forces the next message to be GET / blah if it is a
handshake.

2. for every request mark as `new` in core.c:proxenet_process_http_request(),
try to determine if the GET request is a WebSocket handshake. If so, update the
request headers (`proto_type` and `proto` fields) to mark the request as WS (or
WSS if ssl intercepted) so that further iteraction in
proxenet_process_http_request() main loop does not conflict with regular HTTP
(or HTTPS) requests.
  • Loading branch information
hugsy committed Nov 26, 2016
1 parent 402a558 commit dd66308
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 36 deletions.
41 changes: 34 additions & 7 deletions core.c
Original file line number Diff line number Diff line change
Expand Up @@ -589,14 +589,17 @@ void proxenet_process_http_request(sock_t server_socket)
}

/* is it WebSocket? */
if(req.http_infos.proto_type == WS || req.http_infos.proto_type == WSS) {
/*if(req.http_infos.proto_type == WS || req.http_infos.proto_type == WSS) {
proxenet_xfree(req.data);
is_new_http_connection = true;
continue;
}
}*/

/* is the new request for HTTPS? */
if (req.is_ssl) {
if (req.is_ssl){
/*
* If the request was SSL/TLS interecepted, continue the loop for the
* next HTTP request (GET/POST/etc.).
*/

if (req.do_intercept == false) {
#ifdef DEBUG
Expand All @@ -619,8 +622,20 @@ void proxenet_process_http_request(sock_t server_socket)
xlog(LOG_ERROR, "%s\n", "Failed to establish interception");
proxenet_xfree(req.data);
break;

} else if (strcmp(req.http_infos.method, "CONNECT")==0){
/*
* If here, the connection is not SSL/TLS based *but* the client
* asked for a CONNECT. It is likely a WebSocket upgrade, so mark the
* connection as `new` as continue the loop to get the HTTP Upgrade
* GET request.
*/
proxenet_xfree(req.data);
is_new_http_connection = true;
continue;
}


is_new_http_connection = true;
}

Expand Down Expand Up @@ -658,7 +673,19 @@ void proxenet_process_http_request(sock_t server_socket)
default:
break;
}

/*
* Probe the new connection for a WebSocket upgrade (according to
* RFC 6455).
*/
if (prepare_websocket(&req) < 0){
xlog(LOG_ERROR, "%s\n", "An error occured while preparing WebSocket, bailing");
proxenet_xfree(req.data);
break;
}

} else {

/* if here, at least 1 request has been to server */
/* so simply forward */
/* e.g. using HTTP/1.1 100 Continue */
Expand All @@ -679,11 +706,11 @@ void proxenet_process_http_request(sock_t server_socket)


if (is_ssl)
retcode = ie_compat_read_post_body(server_socket, &req, &(ssl_context.server.context));
retcode = get_http_request_body(server_socket, &req, &(ssl_context.server.context));
else
retcode = ie_compat_read_post_body(server_socket, &req, NULL);
retcode = get_http_request_body(server_socket, &req, NULL);
if (retcode < 0){
xlog(LOG_ERROR, "%s\n", "Extending IE POST: failed");
xlog(LOG_ERROR, "get_http_request_body() failed: retcode=%d\n", retcode);
proxenet_xfree(req.data);
break;
}
Expand Down
77 changes: 59 additions & 18 deletions http.c
Original file line number Diff line number Diff line change
Expand Up @@ -431,11 +431,6 @@ int parse_http_request(request_t *req)
}
}

/* char *upgrade_header = get_header_by_name(buf, "Upgrade:"); */
/* if (upgrade_header){ */
/* if (strcmp(upgrade_header, "websocket")==0){ */
/* format_ws_request() */

return 0;


Expand Down Expand Up @@ -717,25 +712,19 @@ int create_http_socket(request_t* req, sock_t* server_sock, sock_t* client_sock,
return -1;
}

/* From WebSocket RFC (6455):
/*
* From WebSocket RFC (6455):
* "The method of the request MUST be GET, and the HTTP version MUST
* be at least 1.1."
*
* This means that if the next message from Web Browser does not start with GET,
* we can assume the connection is SSL/TLS (i.e. HTTPS or WSS).
*/
if(strcmp(peek_read, "GET")!=0){
ssl_ctx->use_ssl = req->is_ssl = true;
req->http_infos.proto_type = HTTPS;
return create_ssl_socket_with_interception(req, client_sock, server_sock, ssl_ctx);
}

xlog(LOG_INFO, "%s\n", "Upgrading to WebSocket");
if(http_infos->port != HTTP_DEFAULT_PORT){
req->http_infos.proto_type = WSS;
req->http_infos.proto = WSS_STRING;
req->http_infos.port = WSS_DEFAULT_PORT;
} else {
req->http_infos.proto_type = WS;
req->http_infos.proto = WS_STRING;
req->http_infos.port = WS_DEFAULT_PORT;
}
}
return 0;
}
Expand All @@ -749,7 +738,7 @@ int create_http_socket(request_t* req, sock_t* server_sock, sock_t* client_sock,
*
* @return 0 if successful, -1 otherwise
*/
int ie_compat_read_post_body(sock_t sock, request_t* req, proxenet_ssl_context_t* sslctx)
int get_http_request_body(sock_t sock, request_t* req, proxenet_ssl_context_t* sslctx)
{
int nb;
size_t old_len, body_len;
Expand Down Expand Up @@ -809,3 +798,55 @@ int ie_compat_read_post_body(sock_t sock, request_t* req, proxenet_ssl_context_t

return 0;
}


/**
* If a GET request is received, check if it is part of a WebSocket handshake (as defined in
* https://tools.ietf.org/html/rfc6455#section-4.2.1)
*
* @param req is a pointer to the request structure
* @return 0 if no error occured, but the request is not a WS upgrade message
* @return 1 if no error occured, and the request is a WS upgrade message
* @return -1 if an error occured
*/
int prepare_websocket(request_t* req)
{
int res = 0;
char *upgrade_header, *connection_header;

xlog(LOG_DEBUG, "testing websocket for req #%d\n", req->id);

connection_header = get_header_by_name(req->data, "Connection: ");
upgrade_header = get_header_by_name(req->data, "Upgrade: ");

if(connection_header && strcasestr(connection_header, "Upgrade") && \
upgrade_header && strcasecmp(upgrade_header, "WebSocket")==0){

xlog(LOG_INFO, "Upgrading request %d to WebSocket\n", req->id);

/* And header the request status accordingly */
if (req->is_ssl){
req->http_infos.proto_type = WSS;
req->http_infos.proto = WSS_STRING;
} else {
req->http_infos.proto_type = WS;
req->http_infos.proto = WS_STRING;
}

update_http_infos_uri(req);

res = 1;
}

#ifdef DEBUG
xlog(LOG_DEBUG, "Processing WebSocket handshake for request #%d ('%s')\n",
req->id, req->http_infos.uri);
#endif

if(connection_header)
proxenet_xfree(connection_header);
if(upgrade_header)
proxenet_xfree(upgrade_header);

return res;
}
3 changes: 2 additions & 1 deletion http.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ int format_http_request(request_t*);
int format_ws_request(request_t*);
int parse_http_request(request_t*);
void free_http_infos(http_infos_t *);
int ie_compat_read_post_body(sock_t, request_t*, proxenet_ssl_context_t*);
int get_http_request_body(sock_t, request_t*, proxenet_ssl_context_t*);
int prepare_websocket(request_t*);

#endif /* _HTTP_H */
20 changes: 10 additions & 10 deletions utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,23 +243,23 @@ char* proxenet_xstrdup2(const char *data)
*/
void proxenet_lstrip(char* str)
{
size_t i, j, d;
size_t i, j;
size_t len = strlen(str);
char* tmp;

if (!len)
if (len==0)
return;

for(i=0; i<=len-1 && (str[i]=='\t' || str[i]=='\n' || str[i]==' '); i++);
if(i == len-1)
return;

d = len-i;
for(j=0; j<d; j++, i++)
str[j] = str[i];

for(j=i-1; j<len; j++)
str[j] = '\x00';

j = len-i;
tmp = alloca(j+1);
memset(tmp, '\x00', j+1);
memcpy(tmp, str+i, j);
memcpy(str, tmp, j);
memset(str+j, '\x00', len-j);
return;
}

Expand All @@ -275,7 +275,7 @@ void proxenet_rstrip(char* str)
size_t i, j;
size_t len = strlen(str);

if (!len)
if (len==0)
return;

for(i=len-1; i && (str[i]=='\t' || str[i]=='\n' || str[i]==' '); i--);
Expand Down

0 comments on commit dd66308

Please sign in to comment.