Ejemplo n.º 1
0
/**
 * Clean heap allocated block, and free it.
 *
 * @param buf : buffer to zero-ize
 * @param buflen : buf length
 */
void proxenet_xclean(void* buf, size_t buflen)
{
        proxenet_xzero(buf, buflen);
        proxenet_xfree(buf);
        return;
}
Ejemplo n.º 2
0
int create_http_socket(char* http_request, sock_t* server_sock, sock_t* client_sock, ssl_context_t* ssl_ctx) 
{
	http_request_t http_infos;
	int retcode;
	char* err;
	char sport[7] = {0, };

	err = NULL;
	proxenet_xzero(&http_infos, sizeof(http_request_t));
	http_infos.method = NULL;
	http_infos.hostname = NULL;
	http_infos.request_uri = NULL;
	
	/* get target from string and establish client socket to dest */
	if (get_url_information(http_request, &http_infos) == false) {
		xlog(LOG_ERROR, "%s\n", "Failed to extract valid parameters from URL.");
		return -1;
	}

	ssl_ctx->use_ssl = http_infos.is_ssl;
	snprintf(sport, 6, "%d", http_infos.port);
	
	retcode = create_connect_socket(http_infos.hostname, sport, &err);
	if (retcode < 0) {
		if (err)
			generic_http_error_page(*server_sock, err);
		else
			generic_http_error_page(*server_sock, "Unknown error in <i>create_connect_socket</i>");
		
		retcode = -1;
		
	} else {
		*client_sock = retcode;
		
		/* if ssl, set up ssl interception */
		if (http_infos.is_ssl) {
			
			/* 1. set up proxy->server ssl session */ 
			if(proxenet_ssl_init_client_context(&(ssl_ctx->client)) < 0) {
				retcode = -1;
				goto http_sock_end;
			}

			proxenet_ssl_wrap_socket(&(ssl_ctx->client.context), client_sock);
			if (proxenet_ssl_handshake(&(ssl_ctx->client.context)) < 0) {
				xlog(LOG_ERROR, "%s\n", "proxy->server: handshake");
				retcode = -1;
				goto http_sock_end;
			}
#ifdef DEBUG
			xlog(LOG_DEBUG, "%s\n", "SSL handshake with server done");
#endif
			proxenet_write(*server_sock,
				       "HTTP/1.0 200 Connection established\r\n\r\n",
				       39);
			
			/* 2.set up proxy->browser ssl session  */
			if(proxenet_ssl_init_server_context(&(ssl_ctx->server)) < 0) {
				retcode = -1;
				goto http_sock_end;
			}

			proxenet_ssl_wrap_socket(&(ssl_ctx->server.context), server_sock);
			if (proxenet_ssl_handshake(&(ssl_ctx->server.context)) < 0) {
				xlog(LOG_ERROR, "handshake proxy->client '%s:%d' failed\n",
				     http_infos.hostname, http_infos.port);
				retcode = -1;
				goto http_sock_end;
			}
			
#ifdef DEBUG
			xlog(LOG_DEBUG, "%s\n", "SSL Handshake with client done");
#endif
		}
	}
	
http_sock_end:
	proxenet_xfree(http_infos.method);
	proxenet_xfree(http_infos.hostname);
	proxenet_xfree(http_infos.request_uri);
	
	return retcode;
}
Ejemplo n.º 3
0
/**
 *
 * request MUST be like
 * METHOD proto://hostname[:port][/location][?param=value....]\r\n
 * cf. RFC2616
 */
bool get_url_information(char* request, http_request_t* http)
{ 
	char *start_pos, *cur_pos, *end_pos;
	unsigned int str_len;
	
	str_len = -1;
	cur_pos = NULL;
	
	
	/* find method */
	start_pos = index(request, ' ');
	if (start_pos == NULL) {
		xlog(LOG_ERROR, "%s\n", "Malformed HTTP Header");
		return false;
	}
	
	end_pos = index(start_pos+1, ' ');
	if (end_pos==NULL) {
		xlog(LOG_ERROR, "%s\n", "Malformed HTTP Header");
		return false;
	}
	
	
	str_len = start_pos-request ; 
	http->method = (char*)proxenet_xmalloc(str_len +1);
	memcpy(http->method, request, str_len);
	
	++start_pos;
	
	/* get proto */
	if (!strncmp(start_pos,"http://", 7)) {
		http->proto = "http";
		http->port = 80;
		start_pos += 7;
		
	} else if (!strncmp(start_pos,"https://", 8)) {
		http->proto = "https";
		http->port = 443;
		http->is_ssl = true;
		start_pos += 8;
		
	} else if (!strcmp(http->method, "CONNECT")) {
		http->proto = "https";
		http->port = 443;
		http->is_ssl = true;
		
	} else {
		xlog(LOG_ERROR, "%s\n", "Malformed HTTP/HTTPS URL, unknown proto");
		xlog(LOG_DEBUG, "%s\n", request);
		proxenet_xfree(http->method);
		return false;
	}
	
	cur_pos = start_pos;
	
	/* get hostname */
	for(; *cur_pos && *cur_pos!=':' && *cur_pos!='/' && cur_pos<end_pos; cur_pos++);
	str_len = cur_pos - start_pos;
	http->hostname = (char*)proxenet_xmalloc(str_len+1);
	memcpy(http->hostname, start_pos, str_len);
	
	/* get port if set explicitly (i.e ':<port_num>'), otherwise default */
	if(*cur_pos == ':') {
		cur_pos++;
		http->port = (unsigned short)atoi(cur_pos);
		for(;*cur_pos!='/' && cur_pos<end_pos;cur_pos++);
	}
	
	/* get request_uri (no need to parse) */
	str_len = end_pos - cur_pos;
	if (str_len > 0) {
		http->request_uri = (char*) proxenet_xmalloc(str_len+1);
		memcpy(http->request_uri, cur_pos, str_len);
	} else {
		http->request_uri = (char*) proxenet_xmalloc(2);
		*(http->request_uri) = '/';
	}
	
	
#ifdef DEBUG
	xlog(LOG_DEBUG, "URL: %s %s://%s:%d%s\n",
	     http->method,
	     http->proto,
	     http->hostname,
	     http->port,
	     http->request_uri);
#endif 
	
	return true;
}
Ejemplo n.º 4
0
static int proxenet_apply_plugins(request_t *request)
{
	plugin_t *p = NULL;
	char *old_data = NULL;;
	char* (*plugin_function)(plugin_t*, request_t*) = NULL;
	
	for (p=plugins_list; p!=NULL; p=p->next) {  
		
		if (p->state == INACTIVE)
			continue;
	
		switch (p->type) {
			
#ifdef _PYTHON_PLUGIN 
			case _PYTHON_:
				plugin_function = proxenet_python_plugin;
				break;
#endif
				
#ifdef _C_PLUGIN
			case _C_:
				plugin_function = proxenet_c_plugin;
				break;
#endif	  

#ifdef _RUBY_PLUGIN
			case _RUBY_:
				plugin_function = proxenet_ruby_plugin;
				break;
#endif	  

#ifdef _PERL_PLUGIN
			case _PERL_:
				plugin_function = proxenet_perl_plugin;
				break;
#endif	  

#ifdef _LUA_PLUGIN
			case _LUA_:
				plugin_function = proxenet_lua_plugin;
				break;
#endif	  
				
			default:
				xlog(LOG_CRITICAL, "Type %d not supported (yet)\n", p->type);
				return -1;
		}

#ifdef DEBUG
		xlog(LOG_DEBUG,
		     "Calling %s plugin id %d: %s:%s\n",
		     supported_plugins_str[p->type],
		     p->id,
		     p->name,
		     request->type==REQUEST?CFG_REQUEST_PLUGIN_FUNCTION:CFG_RESPONSE_PLUGIN_FUNCTION);
#endif
		
		old_data = request->data;
		request->data = (*plugin_function)(p, request);
		
		if (request->data) {
			/*
			 * If new_data is different, it means a new buffer was allocated by
			 * (*plugin_function)(). The old_data can then be free-ed.
			 */
			proxenet_xfree(old_data);
			
		} else {
			/* Otherwise (data different or error), use the original data */
			request->data = old_data;
		}

		/* Additionnal check for dummy plugin coder */
		if (!request->data || request->size == 0) {
			xlog(LOG_CRITICAL, "Plugin '%s' is invalid", p->name);
			p->state = INACTIVE;
			
			return -1;
		}
	}
	
	return 0;
}
Ejemplo n.º 5
0
/**
 * This function is called by all threads to treat to process the request and response.
 * It will also apply the plugins.
 */
void proxenet_process_http_request(sock_t server_socket)
{
	sock_t client_socket;
	request_t req;
	int retcode;
	fd_set rfds;
	struct timespec ts;
	ssl_context_t ssl_context;
	bool is_ssl;
	sigset_t emptyset;
	size_t n;
	
	client_socket = retcode = n = -1;
	
	proxenet_xzero(&req, sizeof(request_t));
	proxenet_xzero(&ssl_context, sizeof(ssl_context_t));

	/* wait for any event on sockets */
	for(;;) {
		
		if (server_socket < 0) {
			xlog(LOG_ERROR, "%s\n", "Sock browser->proxy died unexpectedly");
			break;
		}
		
		ts.tv_sec  = HTTP_TIMEOUT_SOCK;
		ts.tv_nsec = 0;
		
		FD_ZERO(&rfds);
		FD_SET(server_socket, &rfds);
		if (client_socket > 0)
			FD_SET(client_socket, &rfds);

		sigemptyset(&emptyset);
		retcode = pselect(FD_SETSIZE, &rfds, NULL, NULL, &ts, &emptyset);
		
		if (retcode < 0) {
			if (errno == EINTR) {
				continue;
			} else {
				xlog(LOG_CRITICAL, "[thread] pselect returned %d: %s\n", retcode, strerror(errno));
				break;
			}
		}

		if (retcode == 0) {
			break;
		}
		
		is_ssl = ssl_context.use_ssl;
		
		/* is there data from web browser to proxy ? */
		if( FD_ISSET(server_socket, &rfds ) ) {	
			n = - 1;
			
			if(is_ssl) {
				n = proxenet_read_all(server_socket,
						      &req.data,
						      &(ssl_context.server.context));
			} else {
				n = proxenet_read_all(server_socket, &req.data, NULL);
			}
#ifdef DEBUG
			xlog(LOG_DEBUG, "[%d] Got %dB from client (%s)\n", req.id, n, (is_ssl)?"SSL":"PLAIN");
#endif
			
			if (n <= 0) 
				break;

			req.size = n;
			
			/* is connection to server not established ? -> new request */
			if (client_socket < 0) {
			
				retcode = create_http_socket(&req, &server_socket, &client_socket, &ssl_context);
				if (retcode < 0) {
					xlog(LOG_ERROR, "[%d] Failed to create %s->server socket\n", req.id, PROGNAME);
					proxenet_xfree(req.data);
					client_socket = -1;
					break;
				}

				
				if (ssl_context.use_ssl) {
					if (ssl_context.server.is_valid && ssl_context.client.is_valid) {
#ifdef DEBUG
						xlog(LOG_DEBUG, "[%d] SSL interception established\n", req.id);
#endif
						proxenet_xfree(req.data);
						continue;
						
					}
					
					xlog(LOG_ERROR, "[%d] Failed to establish interception\n", req.id);
					proxenet_xfree(req.data);
					client_socket = -1;
					break;
				}
			}
			
			req.type   = REQUEST;
			req.id     = get_new_request_id();

			/* check if request is valid  */
			if (!cfg->proxy.host) {
				if (!is_ssl) {
					if (!is_valid_http_request(&req.data, &req.size)) {
							proxenet_xfree(req.data);
							client_socket = -1;
							break;
					}
				} else {
					set_https_infos(&req);
				}
			}


			if (cfg->verbose) {
				xlog(LOG_INFO, "New request %d to '%s:%d'\n",
				     req.id,
				     req.http_infos.hostname,
				     req.http_infos.port);
				
				if (cfg->verbose > 1)
					xlog(LOG_INFO, "%s %s://%s:%d%s %s\n",
					     req.http_infos.method,
					     req.http_infos.proto,
					     req.http_infos.hostname,
					     req.http_infos.port,
					     req.http_infos.uri,
					     req.http_infos.version);
					     
			}

#ifdef DEBUG
			xlog(LOG_DEBUG, "[%d] Sending buffer %d bytes (%s) - pre-plugins\n",
			     req.id, req.size, (req.http_infos.is_ssl)?"SSL":"PLAIN");
#endif
			/* hook request with all plugins in plugins_list  */
			if ( proxenet_apply_plugins(&req) < 0) {
				/* extremist action: any error on any plugin discard the whole request */
				req.id = 0;
				proxenet_xfree( req.data );
				continue;
			}
			
#ifdef DEBUG
			xlog(LOG_DEBUG, "[%d] Sending buffer %d bytes (%s) - post-plugins\n",
			     req.id, req.size, (req.http_infos.is_ssl)?"SSL":"PLAIN");
#endif
			/* send modified data */
			if (is_ssl) {
				retcode = proxenet_ssl_write(client_socket, req.data, req.size,
							     &(ssl_context.client.context));
			} else {
				retcode = proxenet_write(client_socket, req.data, req.size);
			}

			proxenet_xfree(req.data);

			if (retcode < 0) {
				xlog(LOG_ERROR, "[%d] %s\n", req.id, "Failed to write to server");
				if (req.id)
					req.id = 0;
				break;
			}
			
		} /* end FD_ISSET(data_from_browser) */
		
		
		/* is there data from remote server to proxy ? */
		if( client_socket > 0 && FD_ISSET(client_socket, &rfds ) ) {
			n = -1;

			if (is_ssl)
				n = proxenet_read_all(client_socket, &req.data, &ssl_context.client.context);
			else
				n = proxenet_read_all(client_socket, &req.data, NULL);
			
#ifdef DEBUG
			xlog(LOG_DEBUG, "[%d] Got %dB from server\n", req.id, n);
#endif
			
			if (n <= 0)
				break;

			/* update request data structure */
			req.type   = RESPONSE;
			req.size   = n;
			
			/* execute response hooks */
			if ( proxenet_apply_plugins(&req) < 0) {
				/* extremist action: any error on any plugin discard the whole request */
				req.id = 0;
				proxenet_xfree(req.data);
				continue;
			}

			/* send modified data to client */
			if (is_ssl)
				retcode = proxenet_ssl_write(server_socket, req.data, req.size, &ssl_context.server.context);
			else
				retcode = proxenet_write(server_socket, req.data, req.size);
			
			if (retcode < 0) {
				xlog(LOG_ERROR, "[%d] %s\n", req.id, "proxy->client: write failed");
			}
			
			proxenet_xfree(req.data);

		}  /* end FD_ISSET(data_from_server) */
		
	}  /* end for(;;) { select() } */

	
	if (req.id) {
#ifdef DEBUG
		xlog(LOG_DEBUG, "Free-ing request %d\n", req.id);
#endif
		proxenet_xfree(req.http_infos.method);
		proxenet_xfree(req.http_infos.hostname);
		proxenet_xfree(req.http_infos.uri);
		proxenet_xfree(req.http_infos.version);
	}
	
	/* close client socket */
	if (client_socket > 0) {
#ifdef DEBUG
		xlog(LOG_DEBUG, "Closing proxy->server socket #%d\n", client_socket);
#endif		
		if (ssl_context.client.is_valid) {
			proxenet_ssl_finish(&(ssl_context.client), false);
			close_socket_ssl(client_socket, &ssl_context.client.context);
		
		} else {
			close_socket(client_socket);
		}
	}
	
	
	/* close local socket */
	if (server_socket > 0) {
#ifdef DEBUG
		xlog(LOG_DEBUG, "Closing browser->proxy socket #%d\n", server_socket);
#endif		
		if (ssl_context.server.is_valid) {
			proxenet_ssl_finish(&(ssl_context.server), true);
			close_socket_ssl(server_socket, &ssl_context.server.context);
			
		} else {
			close_socket(server_socket);
		}
	}

	/* and that's all folks */
	return;
}
Ejemplo n.º 6
0
/**
 * Establish a connection from proxenet -> server. If proxy forwarding configured, then process
 * request to other proxy.
 * 
 */
int create_http_socket(request_t* req, sock_t* server_sock, sock_t* client_sock, ssl_context_t* ssl_ctx) 
{
	int retcode;
	char *host, *port;
	char sport[6] = {0, };
	http_request_t* http_infos = &req->http_infos;
	bool use_proxy = (cfg->proxy.host != NULL) ;

	/* get target from string and establish client socket to dest */
	if (get_url_information(req->data, http_infos) == false) {
		xlog(LOG_ERROR, "%s\n", "Failed to extract valid parameters from URL.");
		return -1;
	}

	
#ifdef DEBUG
	char* full_uri = get_request_full_uri(req);
	xlog(LOG_DEBUG, "URL: %s\n", full_uri);
	proxenet_xfree(full_uri);
#endif
	
	ssl_ctx->use_ssl = http_infos->is_ssl;
	snprintf(sport, 5, "%u", http_infos->port);

	/* do we forward to another proxy ? */
	if (use_proxy) {
		host = cfg->proxy.host;
		port = cfg->proxy.port;
		
	} else {
		host = http_infos->hostname;
		port = sport;
	}
	
	retcode = create_connect_socket(host, port);
	if (retcode < 0) {
		if (errno)
			generic_http_error_page(*server_sock, strerror(errno));
		else
			generic_http_error_page(*server_sock, "Unknown error in <i>create_connect_socket</i>");
		
		retcode = -1;
		
	} else {
		*client_sock = retcode;
		
		/* if ssl, set up ssl interception */
		if (http_infos->is_ssl) {

			if (use_proxy) {
				char *connect_buf = NULL;
				
				/* 0. set up proxy->proxy ssl session (i.e. forward CONNECT request) */ 
				retcode = proxenet_write(*client_sock, req->data, req->size);
				if (retcode < 0) {
					xlog(LOG_ERROR, "%s failed to CONNECT to proxy\n", PROGNAME);
					return -1;
				}

				/* read response */
				retcode = proxenet_read_all(*client_sock, &connect_buf, NULL);
				if (retcode < 0) {
					xlog(LOG_ERROR, "%s Failed to read from proxy\n", PROGNAME);
					return -1;
				}

				/* expect HTTP 200 */
				if (   (strncmp(connect_buf, "HTTP/1.0 200", 12) != 0) 
				    && (strncmp(connect_buf, "HTTP/1.1 200", 12) != 0)) {
					xlog(LOG_ERROR, "%s->proxy: bad HTTP version\n", PROGNAME);
					if (cfg->verbose)
							xlog(LOG_ERROR, "Received %s\n", connect_buf);
					
					return -1;
				}
			}

			/* 1. set up proxy->server ssl session */ 
			if(proxenet_ssl_init_client_context(&(ssl_ctx->client)) < 0) {
				return -1;
			}
			
			proxenet_ssl_wrap_socket(&(ssl_ctx->client.context), client_sock);
			if (proxenet_ssl_handshake(&(ssl_ctx->client.context)) < 0) {
				xlog(LOG_ERROR, "%s->server: handshake\n", PROGNAME);
				return -1;
			}

#ifdef DEBUG
			xlog(LOG_DEBUG, "%s %d %d\n", "SSL handshake with server done",
			     *client_sock,
			     *server_sock);
#endif
			if (proxenet_write(*server_sock,
					   "HTTP/1.0 200 Connection established\r\n\r\n",
					   39) < 0){
				return -1;
			}

			/* 2. set up proxy->browser ssl session  */
			if(proxenet_ssl_init_server_context(&(ssl_ctx->server)) < 0) {
				return -1;
			}

			proxenet_ssl_wrap_socket(&(ssl_ctx->server.context), server_sock);
			if (proxenet_ssl_handshake(&(ssl_ctx->server.context)) < 0) {
				xlog(LOG_ERROR, "handshake %s->client '%s:%d' failed\n",
				     PROGNAME, http_infos->hostname, http_infos->port);
				return -1;
			}

#ifdef DEBUG
			xlog(LOG_DEBUG, "%s\n", "SSL Handshake with client done");
#endif
		}
	}
	
	
	return retcode;
}
Ejemplo n.º 7
0
/**
 * This function is called by all threads to treat to process the request and response.
 * It will also apply the plugins.
 *
 * @param server_socket is the socket received by the main thread from the web browser (acting like server
 * to web browser)
 */
void proxenet_process_http_request(sock_t server_socket)
{
        sock_t client_socket;
        request_t req;
        int retcode, n;
        fd_set rfds;
        struct timespec ts;
        ssl_context_t ssl_context;
        bool is_ssl;
        sigset_t emptyset;
        bool is_new_http_connection = false;

        client_socket = retcode = n = -1;
        proxenet_xzero(&req, sizeof(request_t));
        proxenet_xzero(&ssl_context, sizeof(ssl_context_t));

        /* wait for any event on sockets */
        while(proxy_state == ACTIVE) {

                if (server_socket < 0) {
                        xlog(LOG_ERROR, "sock browser->%s (#%d) died unexpectedly\n", PROGNAME, server_socket);
                        break;
                }

                ts.tv_sec  = HTTP_TIMEOUT_SOCK;
                ts.tv_nsec = 0;

                FD_ZERO(&rfds);
                FD_SET(server_socket, &rfds);
                if (client_socket > 0)
                        FD_SET(client_socket, &rfds);

                sigemptyset(&emptyset);
                retcode = pselect(FD_SETSIZE, &rfds, NULL, NULL, &ts, &emptyset);
                if (retcode < 0) {
                        if (errno == EINTR) {
                                continue;
                        } else {
                                xlog(LOG_CRITICAL, "[thread] pselect returned %d: %s\n", retcode, strerror(errno));
                                break;
                        }
                }

                if (retcode == 0) {
                        continue;
                }

                is_ssl = ssl_context.use_ssl;

                /* is there data from web browser to proxy ? */
                if( FD_ISSET(server_socket, &rfds ) ) {

                        if(is_ssl && req.do_intercept) {
                                n = proxenet_read_all(server_socket,
                                                      &req.data,
                                                      &(ssl_context.server.context));
                        } else {
                                n = proxenet_read_all(server_socket, &req.data, NULL);
                        }

#ifdef DEBUG
                        xlog(LOG_DEBUG, "Got %dB from client (%s srv_sock=#%d intercept_flag=%s)\n",
                             n, is_ssl?"SSL":"PLAIN", server_socket,
                             req.do_intercept?"true":"false");
#endif

                        if (n < 0) {
                                xlog(LOG_ERROR, "%s\n", "read() failed, end thread");
                                break;
                        }

                        if (n == 0){
#ifdef DEBUG
                                xlog(LOG_DEBUG, "%s\n", "Socket EOF from client");
#endif
                                break;
                        }


                        /* from here, n can only be positive */
                        req.size = (size_t) n;
                        bytes_sent += n;

                        if (req.id > 0 && !req.do_intercept){
#ifdef DEBUG
                                xlog(LOG_DEBUG, "Intercept disabled for browser->'%s'\n", req.http_infos.hostname);
#endif
                                goto send_to_server;
                        }

                        /* proxy keep-alive */
                        if (req.id > 0){
                                request_t* old_req = (request_t*)proxenet_xmalloc(sizeof(request_t));
                                memcpy(old_req, &req, sizeof(request_t));
                                char* host = proxenet_xstrdup2( req.http_infos.hostname );

                                free_http_infos(&(req.http_infos));

                                if (update_http_infos(&req) < 0){
                                        xlog(LOG_ERROR, "Failed to update HTTP information for request %d\n", req.id);
                                        proxenet_xfree( host );
                                        proxenet_xfree( old_req );
                                        req.id = 0;
                                        break;
                                }

                                if (strcmp( host, req.http_infos.hostname )){
                                        /* reset the client connection parameters */
                                        if (cfg->verbose)
                                                xlog(LOG_INFO, "Reusing sock=%d (old request=%d, old sock=%d) %s/%s\n",
                                                     server_socket, req.id, client_socket, host, req.http_infos.hostname );
                                        proxenet_close_socket(client_socket, &(ssl_context.client));
                                        free_http_infos(&(req.http_infos));
                                        client_socket = -1;
                                }

                                proxenet_xclean( old_req, sizeof(request_t) );
                                proxenet_xfree( host );
                        }

                        req.type = REQUEST;
                        req.id = get_new_request_id();

                        /* is connection to server not established ? -> new request */
                        if ( client_socket < 0) {
                                retcode = create_http_socket(&req, &server_socket, &client_socket, &ssl_context);
                                if (retcode < 0) {
                                        xlog(LOG_ERROR, "Failed to create %s->server socket\n", PROGNAME);
                                        proxenet_xfree(req.data);
                                        req.id = 0;
                                        break;
                                }


                                if (ssl_context.use_ssl) {
                                        req.is_ssl = true;

                                        if (req.do_intercept == false) {
#ifdef DEBUG
                                                xlog(LOG_DEBUG, "SSL interception client <-> %s <-> server disabled\n", PROGNAME);
#endif
                                                proxenet_xfree(req.data);
                                                req.type = REQUEST;
                                                req.id = get_new_request_id();
                                                continue;

                                        } else if (ssl_context.server.is_valid && ssl_context.client.is_valid) {
#ifdef DEBUG
                                                xlog(LOG_DEBUG, "SSL interception client <-> %s <-> server established\n", PROGNAME);
#endif
                                                proxenet_xfree(req.data);
                                                is_new_http_connection = true;
                                                continue;
                                        }

                                        xlog(LOG_ERROR, "%s\n", "Failed to establish interception");
                                        proxenet_xfree(req.data);
                                        break;
                                }

                                is_new_http_connection = true;
                        }



                        /* if proxenet does not relay to another proxy */
                        if (!cfg->proxy.host) {

                                if (is_new_http_connection) {

                                        if (is_ssl) {
                                                /*
                                                 * SSL request fields still have the values gathered in the CONNECT
                                                 * Those values must be updated to reflect the real request
                                                 */
                                                free_http_infos(&(req.http_infos));
                                                retcode = update_http_infos(&req);
                                        } else {
                                                /*
                                                 * Format requests
                                                 * GET http://foo/bar.blah HTTP/1.1 ...
                                                 * into
                                                 * GET /bar.blah HTTP/1.1 ...
                                                 */
                                                retcode = format_http_request(&req.data, &req.size);
                                        }
                                } else {
                                        /* if here, at least 1 request has been to server */
                                        /* so simply forward  */
                                        /* e.g. using HTTP/1.1 100 Continue */
#ifdef DEBUG
                                        xlog(LOG_DEBUG, "Resuming stream '%d'->'%d'\n", client_socket, server_socket);
#endif
                                        free_http_infos(&(req.http_infos));
                                        retcode = update_http_infos(&req);
                                }

                                if (retcode < 0){
                                        xlog(LOG_ERROR, "Failed to update %s information in request %d\n",
                                             is_ssl?"HTTPS":"HTTP", req.id);
                                        proxenet_xfree(req.data);
                                        break;
                                }
                        }


                        if(cfg->ie_compat){
                                if (is_ssl)
                                        retcode = ie_compat_read_post_body(server_socket, &req, &(ssl_context.server.context));
                                else
                                        retcode = ie_compat_read_post_body(server_socket, &req, NULL);
                                if (retcode < 0){
                                        xlog(LOG_ERROR, "%s\n", "Extending IE POST: failed");
                                        proxenet_xfree(req.data);
                                        break;
                                }
                        }


                        /* apply plugins for requests (from browser to server) */
                        if (cfg->verbose) {
                                xlog(LOG_INFO, "%s request to '%s:%d'\n",
                                     is_ssl?"SSL":"plain", req.http_infos.hostname, req.http_infos.port);

                                if (cfg->verbose > 1)
                                        xlog(LOG_INFO, "%s %s %s\n",
                                             req.http_infos.method, req.http_infos.uri, req.http_infos.version);
                        }

#ifdef DEBUG
                        xlog(LOG_DEBUG, "Request %d pre-plugins: buflen:%lu\n",
                             req.id, req.size);
#endif
                        /* hook request with all plugins in plugins_list  */
                        if ( proxenet_apply_plugins(&req) < 0) {
                                /* extremist action: any error on any plugin discard the whole request */
                                proxenet_xfree( req.data );
                                break;
                        }
#ifdef DEBUG
                        xlog(LOG_DEBUG, "Request %d post-plugins: buflen:%lu\n",
                             req.id, req.size);

                        if(cfg->verbose > 2)
                                proxenet_hexdump(req.data, req.size);
#endif

                send_to_server:
                        /* send modified data */
                        if (is_ssl && req.do_intercept) {
                                retcode = proxenet_ssl_write(&(ssl_context.client.context), req.data, req.size);
                        } else {
                                retcode = proxenet_write(client_socket, req.data, req.size);
                        }

                        /* reset data */
                        proxenet_xfree(req.data);
                        req.size = 0;

                        if (retcode < 0) {
                                xlog(LOG_ERROR, "[%d] %s\n", req.id, "Failed to write to server");
                                break;
                        }

#ifdef DEBUG
                        xlog(LOG_DEBUG, "Written %d bytes to server (socket=%s socket #%d)\n",
                             retcode, is_ssl?"SSL":"PLAIN", client_socket);
#endif

                } /* end FD_ISSET(data_from_browser) */


                /* is there data from remote server to proxy ? */
                if( client_socket > 0 && FD_ISSET(client_socket, &rfds ) ) {

                        if(req.is_ssl && req.do_intercept) {
                                n = proxenet_read_all(client_socket, &req.data, &ssl_context.client.context);
                        } else {
                                n = proxenet_read_all(client_socket, &req.data, NULL);
                        }

                        if (n < 0){
                                xlog(LOG_ERROR, "read() %s on cli_sock=#%d failed: %d\n",
                                     is_ssl?"SSL":"PLAIN",
                                     client_socket, n);
                                break;
                        }

                        if (n==0){
#ifdef DEBUG
                                xlog(LOG_DEBUG, "Socket EOF from server (cli_sock=#%d)\n",
                                     client_socket);
#endif
                                break;
                        }

                        /* update request data structure */
                        req.type   = RESPONSE;

                        /* from here, n can only be positive */
                        req.size   = (size_t) n;
                        bytes_recv += n;

                        if (req.do_intercept==false){
#ifdef DEBUG
                                xlog(LOG_DEBUG, "Intercept disabled for '%s'->browser\n", req.http_infos.hostname);
#endif
                                goto send_to_client;
                        }

                        /* apply plugins for response (from server to browser) */
#ifdef DEBUG
                        xlog(LOG_DEBUG, "Response %d pre-plugins: buflen:%lu\n",
                             req.id, req.size);
#endif
                        /* execute response hooks */
                        if ( proxenet_apply_plugins(&req) < 0) {
                                /* extremist action: any error on any plugin discard the whole request */
                                proxenet_xfree(req.data);
                                break;
                        }
#ifdef DEBUG
                        xlog(LOG_DEBUG, "Response %d post-plugins: buflen:%lu\n",
                             req.id, req.size);

                        if(cfg->verbose > 2)
                                proxenet_hexdump(req.data, req.size);
#endif

                send_to_client:
                        /* send modified data to client */
                        if (req.is_ssl && req.do_intercept)
                                retcode = proxenet_ssl_write(&(ssl_context.server.context), req.data, req.size);
                        else
                                retcode = proxenet_write(server_socket, req.data, req.size);

                        if (retcode < 0) {
                                xlog(LOG_ERROR, "[%d] %s\n", req.id, "proxy->client: write failed");
                                proxenet_xfree(req.data);
                                break;
                        }

#ifdef DEBUG
                        xlog(LOG_DEBUG, "Written %d bytes to browser (socket=%s socket #%d)\n",
                             retcode, is_ssl?"SSL":"PLAIN", client_socket);
#endif
                        proxenet_xfree(req.data);

                }  /* end FD_ISSET(data_from_server) */

        }  /* end for(;;) { select() } */


        if (req.id) {
                if (cfg->verbose)
                        xlog(LOG_INFO, "End of request %d, cleaning context\n", req.id);

                free_http_infos(&(req.http_infos));
        }


        /* close client socket */
        if (client_socket > 0) {
                if (cfg->verbose >= 2)
                        xlog(LOG_INFO, "Closing %s->server (fd=#%d)\n", PROGNAME, client_socket);

                proxenet_close_socket(client_socket, &(ssl_context.client));
        }


        /* close local socket */
        if (server_socket > 0) {
                if (cfg->verbose >= 2)
                        xlog(LOG_INFO, "Closing browser->%s (fd=#%d)\n", PROGNAME, server_socket);

                proxenet_close_socket(server_socket, &(ssl_context.server));
        }


#ifdef DEBUG
        xlog(LOG_DEBUG, "Request %d: Structures closed, leaving\n", req.id);
#endif
        /* and that's all folks */
        return;
}
Ejemplo n.º 8
0
static int proxenet_apply_plugins(request_t *request)
{
        plugin_t *p = NULL;
        char *old_data = NULL;
        char *res = NULL;
        char* (*plugin_function)(plugin_t*, request_t*) = NULL;

        for (p=plugins_list; p!=NULL; p=p->next) {

                if (p->state == INACTIVE)
                        continue;

                switch (p->type) {

#ifdef _PYTHON_PLUGIN
                        case _PYTHON_:  plugin_function = proxenet_python_plugin; break;
#endif
#ifdef _C_PLUGIN
                        case _C_:       plugin_function = proxenet_c_plugin; break;
#endif
#ifdef _RUBY_PLUGIN
                        case _RUBY_:    plugin_function = proxenet_ruby_plugin; break;
#endif
#ifdef _PERL_PLUGIN
                        case _PERL_:    plugin_function = proxenet_perl_plugin; break;
#endif
#ifdef _LUA_PLUGIN
                        case _LUA_:     plugin_function = proxenet_lua_plugin; break;
#endif
#ifdef _TCL_PLUGIN
                        case _TCL_:     plugin_function = proxenet_tcl_plugin; break;
#endif
#ifdef _JAVA_PLUGIN
                        case _JAVA_:    plugin_function = proxenet_java_plugin; break;
#endif
                        default:
                                xlog(LOG_CRITICAL, "Type %d not supported (yet)\n", p->type);
                                return -1;
                }

#ifdef DEBUG
                xlog(LOG_DEBUG, "Calling '%s:%s' with rid=%d (%s)\n",
                     p->name,
                     request->type==REQUEST?CFG_REQUEST_PLUGIN_FUNCTION:CFG_RESPONSE_PLUGIN_FUNCTION,
                     request->id,
                     supported_plugins_str[p->type]
                     );
#endif

                old_data = request->data;

#ifdef DEBUG
                struct timeval tstart, tend;
                proxenet_xzero(&tstart, sizeof(struct timeval));
                proxenet_xzero(&tend, sizeof(struct timeval));
                gettimeofday(&tstart, NULL);
#endif
                res = (*plugin_function)(p, request);
#ifdef DEBUG
                gettimeofday(&tend, NULL);

                unsigned long sec = tend.tv_sec-tstart.tv_sec;
                unsigned long msec = (tend.tv_usec-tstart.tv_usec)/1000;
                unsigned long usec = (tend.tv_usec-tstart.tv_usec)%1000;

                xlog(LOG_DEBUG, "[%s] '%s:%s' executed in %dsec, %dms, %dus\n",
                     supported_plugins_str[p->type], p->name,
                     request->type==REQUEST?CFG_REQUEST_PLUGIN_FUNCTION:CFG_RESPONSE_PLUGIN_FUNCTION,
                     sec, msec, usec);
#endif

                /*
                 * We consider a plugin execution has failed if one of those conditions is found:
                 * - the plugin_*_apply() function returned NULL
                 * - the new request size is 0
                 */

                if (res == NULL || request->size==0) {
                        /*
                         * If the plugin function returned NULL, it means that an error occured
                         * somewhere in the VM run. To be safe, we disable the plugin, and restore
                         * the previous context.
                         */
                        request->data = old_data;
                        xlog(LOG_ERROR, "Plugin '%s' failed, disabling...\n", p->name);
                        proxenet_plugin_set_state(p, INACTIVE);
                        continue;
                }

                request->data = res;

                if (request->data) {
                        /*
                         * If new_data is different, it means a new buffer was allocated by
                         * (*plugin_function)(). The old_data can then be free-ed.
                         */
                        proxenet_xfree(old_data);

#ifdef DEBUG
                        xlog(LOG_DEBUG,
                             "New data from '%s:%s' on rid=%d\n",
                             request->type==REQUEST?CFG_REQUEST_PLUGIN_FUNCTION:CFG_RESPONSE_PLUGIN_FUNCTION,
                             p->name,
                             p->id);
#endif

                } else {
                        /* Otherwise (data different or error), use the original data */
                        request->data = old_data;

#ifdef DEBUG
                        xlog(LOG_DEBUG,
                             "No new data from '%s:%s' on rid=%d\n",
                             request->type==REQUEST?CFG_REQUEST_PLUGIN_FUNCTION:CFG_RESPONSE_PLUGIN_FUNCTION,
                             p->name,
                             p->id);
#endif
                }
        }

        return 0;
}
Ejemplo n.º 9
0
/**
 * This function updates all the fields of the current request_t with the new values found in the
 * request. Since those values will be useful many times, they are strdup-ed in a specific structure
 * (http_request_t). Those values *must* be free-ed later on.
 *
 * @return 0 if successful, -1 if any error occurs.
 */
int update_http_infos(request_t *req)
{
        char *ptr, *buf, c;

        buf = req->data;

        /* method */
        ptr = strchr(buf, ' ');
        if (!ptr){
                xlog(LOG_ERROR, "%s\n", "Cannot find HTTP method in request");
                if (cfg->verbose)
                        xlog(LOG_ERROR, "Buffer sent:\n%s\n", buf);
                return -1;
        }

        c = *ptr;
        *ptr = '\0';
        req->http_infos.method = proxenet_xstrdup2(buf);
        if (!req->http_infos.method){
                xlog(LOG_ERROR, "%s\n", "strdup(method) failed, cannot pursue...");
                return -1;
        }

        *ptr = c;
        if (!strcmp(req->http_infos.method, "CONNECT")){
                int offset;

                req->is_ssl = true;
                req->http_infos.proto = HTTPS_STRING;
                req->http_infos.port = HTTPS_DEFAULT_PORT;
                offset = ptr - buf + 1;

                if( get_hostname_from_uri(req, offset) < 0 ){
                        xlog(LOG_ERROR, "%s\n", "Failed to get hostname (URI)");
                        goto failed_hostname;
                }

                req->http_infos.path = proxenet_xstrdup2("/");
                req->http_infos.version = proxenet_xstrdup2("HTTP/1.0");

                req->http_infos.uri = get_request_full_uri(req);
                if(!req->http_infos.uri){
                        xlog(LOG_ERROR, "%s\n", "get_request_full_uri() failed");
                        goto failed_uri;
                }

                return 0;
        }


        /* hostname and port */
        if (req->is_ssl){
                req->http_infos.port = HTTPS_DEFAULT_PORT;
                req->http_infos.proto = HTTPS_STRING;
        } else {
                req->http_infos.port = HTTP_DEFAULT_PORT;
                req->http_infos.proto = HTTP_STRING;
        }

        if( get_hostname_from_header(req) < 0 ){
                xlog(LOG_ERROR, "%s\n", "Failed to get hostname (Host header)");
                goto failed_hostname;
        }


        /* path */
        buf = ptr+1;

        if (!strncmp(buf, HTTP_PROTO_STRING, strlen(HTTP_PROTO_STRING))){
                buf = strchr(buf + 8, '/');
        }

        ptr = strchr(buf, ' ');
        if (!ptr){
                xlog(LOG_ERROR, "%s\n", "Cannot find HTTP path in request");
                goto failed_path;
        }

        c = *ptr;
        *ptr = '\0';
        req->http_infos.path = proxenet_xstrdup2(buf);
        if (!req->http_infos.path){
                xlog(LOG_ERROR, "%s\n", "strdup(path) failed, cannot pursue...");
                goto failed_path;
        }
        *ptr = c;

        buf = ptr+1;


        /* version */
        ptr = strchr(req->data, '\r');
        if (!ptr){
                xlog(LOG_ERROR, "%s\n", "Cannot find HTTP version");
                goto failed_version;
        }

        c = *ptr;
        *ptr = '\0';
        req->http_infos.version = proxenet_xstrdup2(buf);
        if (!req->http_infos.version){
                xlog(LOG_ERROR, "%s\n", "strdup(version) failed, cannot pursue...");
                goto failed_version;
        }
        *ptr = c;


        /* refresh uri */
        req->http_infos.uri = get_request_full_uri(req);
        if(!req->http_infos.uri){
                xlog(LOG_ERROR, "%s\n", "get_request_full_uri() failed");
                goto failed_uri;
        }


        if (cfg->verbose) {
                xlog(LOG_INFO, "New request %d to '%s'\n",
                     req->id, req->http_infos.uri);

                if (cfg->verbose >= 2) {
                        xlog(LOG_INFO,
                             "Request HTTP information:\n"
                             "method=%s\n"
                             "proto=%s\n"
                             "hostname=%s\n"
                             "port=%d\n"
                             "path=%s\n"
                             "version=%s\n"
                             ,
                             req->http_infos.method,
                             req->http_infos.proto,
                             req->http_infos.hostname,
                             req->http_infos.port,
                             req->http_infos.path,
                             req->http_infos.version);
                }
        }

        return 0;


failed_uri:
        proxenet_xfree(req->http_infos.version);

failed_version:
        proxenet_xfree(req->http_infos.path);

failed_path:
        proxenet_xfree(req->http_infos.hostname);

failed_hostname:
        proxenet_xfree(req->http_infos.method);

        return -1;
}
Ejemplo n.º 10
0
static int proxenet_apply_plugins(request_t *request)
{
        plugin_t *p = NULL;
        char *old_data = NULL;
        char* (*plugin_function)(plugin_t*, request_t*) = NULL;

        for (p=plugins_list; p!=NULL; p=p->next) {

                if (p->state == INACTIVE)
                        continue;

                switch (p->type) {

#ifdef _PYTHON_PLUGIN
                        case _PYTHON_:  plugin_function = proxenet_python_plugin; break;
#endif
#ifdef _C_PLUGIN
                        case _C_:       plugin_function = proxenet_c_plugin; break;
#endif
#ifdef _RUBY_PLUGIN
                        case _RUBY_:    plugin_function = proxenet_ruby_plugin; break;
#endif
#ifdef _PERL_PLUGIN
                        case _PERL_:    plugin_function = proxenet_perl_plugin; break;
#endif
#ifdef _LUA_PLUGIN
                        case _LUA_:     plugin_function = proxenet_lua_plugin; break;
#endif
#ifdef _TCL_PLUGIN
                        case _TCL_:     plugin_function = proxenet_tcl_plugin; break;
#endif
#ifdef _JAVA_PLUGIN
                        case _JAVA_:    plugin_function = proxenet_java_plugin; break;
#endif
                        default:
                                xlog(LOG_CRITICAL, "Type %d not supported (yet)\n", p->type);
                                return -1;
                }

#ifdef DEBUG
                xlog(LOG_DEBUG, "Calling '%s:%s' with rid=%d (%s)\n",
                     p->name,
                     request->type==REQUEST?CFG_REQUEST_PLUGIN_FUNCTION:CFG_RESPONSE_PLUGIN_FUNCTION,
                     request->id,
                     supported_plugins_str[p->type]
                     );
#endif

                old_data = request->data;

#ifdef DEBUG
                struct timeval tstart, tend;
                proxenet_xzero(&tstart, sizeof(struct timeval));
                proxenet_xzero(&tend, sizeof(struct timeval));
                gettimeofday(&tstart, NULL);
#endif
                request->data = (*plugin_function)(p, request);
#ifdef DEBUG
                gettimeofday(&tend, NULL);
                xlog(LOG_DEBUG, "[%s] '%s:%s' executed in %lusec, %lums\n",
                     supported_plugins_str[p->type], p->name,
                     request->type==REQUEST?CFG_REQUEST_PLUGIN_FUNCTION:CFG_RESPONSE_PLUGIN_FUNCTION,
                     tend.tv_sec-tstart.tv_sec,
                     tend.tv_usec-tstart.tv_usec);
#endif

                if (request->data) {
                        /*
                         * If new_data is different, it means a new buffer was allocated by
                         * (*plugin_function)(). The old_data can then be free-ed.
                         */
                        proxenet_xfree(old_data);

#ifdef DEBUG
                        xlog(LOG_DEBUG,
                             "New data from '%s:%s' on rid=%d\n",
                             request->type==REQUEST?CFG_REQUEST_PLUGIN_FUNCTION:CFG_RESPONSE_PLUGIN_FUNCTION,
                             p->name,
                             p->id);
#endif

                } else {
                        /* Otherwise (data different or error), use the original data */
                        request->data = old_data;

#ifdef DEBUG
                        xlog(LOG_DEBUG,
                             "No new data from '%s:%s' on rid=%d\n",
                             request->type==REQUEST?CFG_REQUEST_PLUGIN_FUNCTION:CFG_RESPONSE_PLUGIN_FUNCTION,
                             p->name,
                             p->id);
#endif
                }

                /* Additionnal check for dummy plugin coder */
                if (!request->data || !request->size) {
                        xlog(LOG_CRITICAL, "Plugin '%s' is invalid, disabling\n", p->name);
                        p->state = INACTIVE;

                        if (cfg->verbose){
                                if(!request->data)
                                        xlog(LOG_CRITICAL, "Plugin '%s' returned a NULL value\n", p->name);
                                else
                                        xlog(LOG_CRITICAL, "Plugin '%s' returned a NULL size\n", p->name);
                        }

                        return -1;
                }
        }

        return 0;
}