2001-09-15 03:50:45 +08:00
|
|
|
/* $Id: reqs.c,v 1.25 2001-09-14 19:50:45 rjkaes Exp $
|
2000-02-17 01:32:49 +08:00
|
|
|
*
|
|
|
|
* This is where all the work in tinyproxy is actually done. Incoming
|
2000-09-12 08:04:42 +08:00
|
|
|
* connections have a new thread created for them. The thread then
|
|
|
|
* processes the headers from the client, the response from the server,
|
|
|
|
* and then relays the bytes between the two.
|
2001-08-28 12:32:14 +08:00
|
|
|
* If TUNNEL_SUPPORT is enabled, then tinyproxy will actually work
|
2000-09-12 08:04:42 +08:00
|
|
|
* as a simple buffering TCP tunnel. Very cool! (Robert actually uses
|
2001-05-27 10:29:06 +08:00
|
|
|
* this feature for a buffering NNTP tunnel.)
|
2000-02-17 01:32:49 +08:00
|
|
|
*
|
2000-09-12 08:04:42 +08:00
|
|
|
* Copyright (C) 1998 Steven Young
|
|
|
|
* Copyright (C) 1999,2000 Robert James Kaes (rjkaes@flarenet.com)
|
|
|
|
* Copyright (C) 2000 Chris Lightfoot (chris@ex-parrot.com)
|
2000-02-17 01:32:49 +08:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
|
|
* later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "tinyproxy.h"
|
2000-09-12 08:04:42 +08:00
|
|
|
|
|
|
|
#include "acl.h"
|
|
|
|
#include "anonymous.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
#include "buffer.h"
|
|
|
|
#include "filter.h"
|
2000-09-12 08:04:42 +08:00
|
|
|
#include "log.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
#include "regexp.h"
|
2000-09-12 08:04:42 +08:00
|
|
|
#include "reqs.h"
|
|
|
|
#include "sock.h"
|
|
|
|
#include "stats.h"
|
|
|
|
#include "utils.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
|
|
|
|
#define HTTP400ERROR "Unrecognizable request. Only HTTP is allowed."
|
|
|
|
#define HTTP500ERROR "Unable to connect to remote server."
|
|
|
|
#define HTTP503ERROR "Internal server error."
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
#define LINE_LENGTH (MAXBUFFSIZE / 3)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write the buffer to the socket. If an EINTR occurs, pick up and try
|
|
|
|
* again.
|
|
|
|
*/
|
2001-09-15 03:50:45 +08:00
|
|
|
static ssize_t safe_write(int fd, const void *buffer, size_t count)
|
2000-09-12 08:04:42 +08:00
|
|
|
{
|
|
|
|
ssize_t len;
|
|
|
|
|
|
|
|
do {
|
|
|
|
len = write(fd, buffer, count);
|
|
|
|
} while (len < 0 && errno == EINTR);
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Matched pair for safe_write(). If an EINTR occurs, pick up and try
|
|
|
|
* again.
|
|
|
|
*/
|
|
|
|
static ssize_t safe_read(int fd, void *buffer, size_t count)
|
|
|
|
{
|
|
|
|
ssize_t len;
|
|
|
|
|
|
|
|
do {
|
|
|
|
len = read(fd, buffer, count);
|
|
|
|
} while (len < 0 && errno == EINTR);
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2001-08-28 12:32:14 +08:00
|
|
|
/*
|
|
|
|
* Remove any new lines or carriage returns from the end of a string.
|
|
|
|
*/
|
|
|
|
static inline void trim(char *string, unsigned int len)
|
|
|
|
{
|
|
|
|
char *ptr;
|
|
|
|
|
|
|
|
assert(string != NULL);
|
|
|
|
assert(len > 0);
|
|
|
|
|
|
|
|
ptr = string + len - 1;
|
|
|
|
while (*ptr == '\r' || *ptr == '\n') {
|
|
|
|
*ptr-- = '\0';
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't let the ptr back past the beginning of the
|
|
|
|
* string.
|
|
|
|
*/
|
|
|
|
if (ptr < string)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-02-17 01:32:49 +08:00
|
|
|
/*
|
2001-09-14 12:56:29 +08:00
|
|
|
* Read in the first line from the client (the request line for HTTP
|
|
|
|
* connections. The request line is allocated from the heap, but it must
|
|
|
|
* be freed in another function.
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2001-09-14 12:56:29 +08:00
|
|
|
static char *read_request_line(struct conn_s *connptr)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2001-09-14 12:56:29 +08:00
|
|
|
char *request_buffer;
|
2001-05-27 10:29:06 +08:00
|
|
|
size_t len;
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
request_buffer = safemalloc(LINE_LENGTH);
|
|
|
|
if (!request_buffer) {
|
|
|
|
log_message(LOG_ERR, "Could not allocate memory in 'read_request_line'");
|
|
|
|
return NULL;
|
2001-09-12 03:26:49 +08:00
|
|
|
}
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
len = readline(connptr->client_fd, request_buffer, LINE_LENGTH);
|
2001-08-27 05:11:55 +08:00
|
|
|
if (len <= 0) {
|
2001-09-14 12:56:29 +08:00
|
|
|
log_message(LOG_ERR, "Client (file descriptor: %d) closed socket before read.", connptr->client_fd);
|
|
|
|
safefree(request_buffer);
|
|
|
|
return NULL;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-08-27 05:11:55 +08:00
|
|
|
/*
|
2001-09-14 12:56:29 +08:00
|
|
|
* Strip the new line and character return from the string.
|
2001-08-27 05:11:55 +08:00
|
|
|
*/
|
2001-09-14 12:56:29 +08:00
|
|
|
trim(request_buffer, len);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
log_message(LOG_CONN, "Request (file descriptor %d): %s",
|
|
|
|
connptr->client_fd, request_buffer);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
return request_buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This structure holds the information pulled from a URL request.
|
|
|
|
*/
|
|
|
|
struct request_s {
|
|
|
|
char *host;
|
|
|
|
char *path;
|
|
|
|
int port;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pull the information out of the URL line.
|
|
|
|
*/
|
|
|
|
static int extract_http_url(const char *url, struct request_s *request)
|
|
|
|
{
|
|
|
|
request->host = safemalloc(strlen(url) + 1);
|
|
|
|
request->path = safemalloc(strlen(url) + 1);
|
|
|
|
|
|
|
|
if (!request->host || !request->path) {
|
|
|
|
log_message(LOG_ERR, "Could not allocate memory in 'extract_http_url'");
|
|
|
|
safefree(request->host);
|
|
|
|
safefree(request->path);
|
|
|
|
|
|
|
|
return -1;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2001-09-14 12:56:29 +08:00
|
|
|
|
|
|
|
if (sscanf(url, "http://%[^:/]:%d%s", request->host, &request->port, request->path) == 3)
|
|
|
|
;
|
|
|
|
else if (sscanf(url, "http://%[^/]%s", request->host, request->path) == 2)
|
|
|
|
request->port = 80;
|
|
|
|
else if (sscanf(url, "http://%[^:/]:%d", request->host, &request->port) == 2)
|
|
|
|
strcpy(request->path, "/");
|
|
|
|
else if (sscanf(url, "http://%[^/]", request->host) == 1) {
|
|
|
|
request->port = 80;
|
|
|
|
strcpy(request->path, "/");
|
|
|
|
} else {
|
|
|
|
log_message(LOG_ERR, "Can't parse URL.");
|
|
|
|
|
|
|
|
safefree(request->host);
|
|
|
|
safefree(request->path);
|
|
|
|
|
|
|
|
return -1;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
/*
|
|
|
|
* Extract the URL from a SSL connection.
|
|
|
|
*/
|
|
|
|
static int extract_ssl_url(const char *url, struct request_s *request)
|
|
|
|
{
|
|
|
|
request->host = safemalloc(strlen(url) + 1);
|
|
|
|
|
|
|
|
if (!request->host) {
|
|
|
|
log_message(LOG_ERR, "Could not allocate memory in 'extract_https_url'");
|
|
|
|
|
|
|
|
return -1;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
if (sscanf(url, "%[^:]:%d", request->host, &request->port) == 2)
|
|
|
|
;
|
|
|
|
else if (sscanf(url, "%s", request->host) == 1)
|
|
|
|
request->port = 443;
|
|
|
|
else {
|
|
|
|
log_message(LOG_ERR, "Can't parse URL.");
|
|
|
|
|
|
|
|
safefree(request->host);
|
|
|
|
return -1;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2001-09-14 12:56:29 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a connection for HTTP connections.
|
|
|
|
*/
|
|
|
|
static int establish_http_connection(struct conn_s *connptr,
|
|
|
|
const char *method,
|
|
|
|
const char *protocol,
|
|
|
|
struct request_s *request)
|
|
|
|
{
|
2001-09-15 03:50:45 +08:00
|
|
|
/*
|
|
|
|
* Send the request line
|
|
|
|
*/
|
|
|
|
if (safe_write(connptr->server_fd, method, strlen(method)) < 0)
|
2001-09-14 12:56:29 +08:00
|
|
|
return -1;
|
2001-09-15 03:50:45 +08:00
|
|
|
if (safe_write(connptr->server_fd, " ", 1) < 0)
|
|
|
|
return -1;
|
|
|
|
if (safe_write(connptr->server_fd, request->path, strlen(request->path)) < 0)
|
|
|
|
return -1;
|
|
|
|
if (safe_write(connptr->server_fd, " ", 1) < 0)
|
|
|
|
return -1;
|
|
|
|
if (safe_write(connptr->server_fd, "HTTP/1.0\r\n", 10) < 0)
|
2001-09-14 12:56:29 +08:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send headers
|
|
|
|
*/
|
2001-09-15 03:50:45 +08:00
|
|
|
if (safe_write(connptr->server_fd, "Host: ", 6) < 0)
|
2001-09-14 12:56:29 +08:00
|
|
|
return -1;
|
2001-09-15 03:50:45 +08:00
|
|
|
if (safe_write(connptr->server_fd, request->host, strlen(request->host)) < 0)
|
2001-09-14 12:56:29 +08:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (safe_write(connptr->server_fd, "\r\n", 2) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send the Connection header since we don't support persistant
|
|
|
|
* connections.
|
|
|
|
*/
|
|
|
|
if (safe_write(connptr->server_fd, "Connection: close\r\n", 19) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
/*
|
|
|
|
* Break the request line apart and figure out where to connect and
|
|
|
|
* build a new request line. Finally connect to the remote server.
|
|
|
|
*/
|
|
|
|
static int process_request(struct conn_s *connptr, char *request_line)
|
|
|
|
{
|
|
|
|
char *method;
|
|
|
|
char *url;
|
|
|
|
char *protocol;
|
|
|
|
|
|
|
|
struct request_s request;
|
|
|
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
size_t request_len;
|
|
|
|
|
|
|
|
/* NULL out all the fields so free's don't cause segfaults. */
|
|
|
|
memset(&request, 0, sizeof(struct request_s));
|
|
|
|
|
|
|
|
request_len = strlen(request_line) + 1;
|
|
|
|
|
|
|
|
method = safemalloc(request_len);
|
|
|
|
url = safemalloc(request_len);
|
|
|
|
protocol = safemalloc(request_len);
|
|
|
|
|
|
|
|
if (!method || !url || !protocol) {
|
|
|
|
log_message(LOG_ERR, "Could not allocate memory in 'process_request'");
|
|
|
|
safefree(method);
|
|
|
|
safefree(url);
|
|
|
|
safefree(protocol);
|
|
|
|
return -1;
|
2000-03-29 00:41:45 +08:00
|
|
|
}
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
ret = sscanf(request_line, "%[^ ] %[^ ] %[^ ]", method, url, protocol);
|
|
|
|
if (ret < 2) {
|
|
|
|
log_message(LOG_ERR, "Bad Request on file descriptor %d", connptr->client_fd);
|
|
|
|
httperr(connptr, 400, "Bad Request. No request found.");
|
|
|
|
|
|
|
|
safefree(method);
|
|
|
|
safefree(url);
|
|
|
|
safefree(protocol);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
} else if (ret == 2) {
|
|
|
|
connptr->simple_req = TRUE;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
if (!url) {
|
|
|
|
log_message(LOG_ERR, "Null URL on file descriptor %d", connptr->client_fd);
|
|
|
|
httperr(connptr, 400, "Bad Request. Null URL.");
|
|
|
|
|
|
|
|
safefree(method);
|
|
|
|
safefree(url);
|
|
|
|
safefree(protocol);
|
|
|
|
|
|
|
|
return -1;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
if (strncasecmp(url, "http://", 7) == 0) {
|
|
|
|
/* Make sure the first four characters are lowercase */
|
|
|
|
memcpy(url, "http", 4);
|
|
|
|
|
|
|
|
if (extract_http_url(url, &request) < 0) {
|
|
|
|
httperr(connptr, 400, "Bad Request. Could not parse URL.");
|
|
|
|
|
|
|
|
safefree(method);
|
|
|
|
safefree(url);
|
|
|
|
safefree(protocol);
|
|
|
|
|
|
|
|
return -1;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2001-09-14 12:56:29 +08:00
|
|
|
connptr->ssl = FALSE;
|
|
|
|
} else if (strcmp(method, "CONNECT") == 0) {
|
|
|
|
if (extract_ssl_url(url, &request) < 0) {
|
|
|
|
httperr(connptr, 400, "Bad Request. Could not parse URL.");
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
safefree(method);
|
|
|
|
safefree(url);
|
|
|
|
safefree(protocol);
|
|
|
|
|
|
|
|
return -1;
|
2000-04-01 06:55:22 +08:00
|
|
|
}
|
2001-09-14 12:56:29 +08:00
|
|
|
connptr->ssl = TRUE;
|
2000-04-01 06:55:22 +08:00
|
|
|
} else {
|
2001-09-14 12:56:29 +08:00
|
|
|
log_message(LOG_ERR, "Unknown URL type on file descriptor %d", connptr->client_fd);
|
|
|
|
httperr(connptr, 400, "Bad Request. Unknown URL type.");
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
safefree(method);
|
|
|
|
safefree(url);
|
|
|
|
safefree(protocol);
|
|
|
|
|
|
|
|
return -1;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
safefree(url);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
#ifdef FILTER_ENABLE
|
2000-09-12 08:04:42 +08:00
|
|
|
/*
|
2001-09-14 12:56:29 +08:00
|
|
|
* Filter restricted domains
|
2000-09-12 08:04:42 +08:00
|
|
|
*/
|
2001-09-14 12:56:29 +08:00
|
|
|
if (config.filter) {
|
|
|
|
if (filter_url(request.host)) {
|
|
|
|
log_message(LOG_ERR, "Proxying refused on filtered domain \"%s\"", request.host);
|
|
|
|
httperr(connptr, 404, "Connection to filtered domain is now allowed.");
|
|
|
|
|
|
|
|
safefree(request.host);
|
|
|
|
safefree(request.path);
|
|
|
|
|
|
|
|
safefree(method);
|
|
|
|
safefree(url);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
/*
|
2001-09-14 12:56:29 +08:00
|
|
|
* Connect to the remote server.
|
2000-09-12 08:04:42 +08:00
|
|
|
*/
|
2001-09-14 12:56:29 +08:00
|
|
|
connptr->server_fd = opensock(request.host, request.port);
|
|
|
|
if (connptr->server_fd < 0) {
|
|
|
|
httperr(connptr, 500, HTTP500ERROR);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
safefree(request.host);
|
|
|
|
safefree(request.path);
|
2000-09-12 08:04:42 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
safefree(method);
|
|
|
|
safefree(protocol);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!connptr->ssl) {
|
|
|
|
if (establish_http_connection(connptr, method, protocol, &request) < 0) {
|
|
|
|
|
|
|
|
safefree(method);
|
|
|
|
safefree(protocol);
|
|
|
|
|
|
|
|
safefree(request.host);
|
|
|
|
safefree(request.path);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
safefree(method);
|
|
|
|
safefree(protocol);
|
|
|
|
|
|
|
|
safefree(request.host);
|
|
|
|
safefree(request.path);
|
|
|
|
|
|
|
|
return 0;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check to see if the line is allowed or not depending on the anonymous
|
2001-08-27 05:11:55 +08:00
|
|
|
* headers which are to be allowed. If the header is found in the
|
|
|
|
* anonymous list return 0, otherwise return -1.
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2000-09-12 08:04:42 +08:00
|
|
|
static int compare_header(char *line)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2001-08-27 05:11:55 +08:00
|
|
|
char *buffer;
|
|
|
|
char *ptr;
|
2000-04-01 04:13:36 +08:00
|
|
|
int ret;
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-08-31 00:51:10 +08:00
|
|
|
if ((ptr = strstr(line, ":")) == NULL)
|
2000-09-12 08:04:42 +08:00
|
|
|
return -1;
|
2000-04-01 04:13:36 +08:00
|
|
|
|
2001-09-09 02:58:37 +08:00
|
|
|
if ((buffer = safemalloc(ptr - line + 1)) == NULL)
|
2000-09-12 08:04:42 +08:00
|
|
|
return -1;
|
2000-04-01 04:13:36 +08:00
|
|
|
|
2001-05-27 10:29:06 +08:00
|
|
|
memcpy(buffer, line, (size_t)(ptr - line));
|
2000-04-01 04:13:36 +08:00
|
|
|
buffer[ptr - line] = '\0';
|
|
|
|
|
2001-08-27 05:11:55 +08:00
|
|
|
ret = anonymous_search(buffer);
|
2000-09-12 08:04:42 +08:00
|
|
|
safefree(buffer);
|
2001-08-27 05:11:55 +08:00
|
|
|
|
|
|
|
return ret;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-09-12 08:04:42 +08:00
|
|
|
* pull_client_data is used to pull across any client data (like in a
|
|
|
|
* POST) which needs to be handled before an error can be reported, or
|
|
|
|
* server headers can be processed.
|
|
|
|
* - rjkaes
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2000-09-12 08:04:42 +08:00
|
|
|
static int pull_client_data(struct conn_s *connptr, unsigned long int length)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2001-09-12 03:26:49 +08:00
|
|
|
char *buffer;
|
2001-05-27 10:29:06 +08:00
|
|
|
ssize_t len;
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-12 03:26:49 +08:00
|
|
|
buffer = safemalloc(MAXBUFFSIZE);
|
|
|
|
if (!buffer)
|
|
|
|
return -1;
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
do {
|
|
|
|
len = safe_read(connptr->client_fd, buffer, min(MAXBUFFSIZE, length));
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
if (len <= 0) {
|
2001-09-12 03:26:49 +08:00
|
|
|
safefree(buffer);
|
2000-09-12 08:04:42 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!connptr->output_message) {
|
|
|
|
if (safe_write(connptr->server_fd, buffer, len) < 0) {
|
2001-09-12 03:26:49 +08:00
|
|
|
safefree(buffer);
|
2000-09-12 08:04:42 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
length -= len;
|
|
|
|
} while (length > 0);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-12 03:26:49 +08:00
|
|
|
safefree(buffer);
|
2000-02-17 01:32:49 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
#ifdef XTINYPROXY_ENABLE
|
2000-02-17 01:32:49 +08:00
|
|
|
/*
|
2000-09-12 08:04:42 +08:00
|
|
|
* Add the X-Tinyproxy header to the collection of headers being sent to
|
|
|
|
* the server.
|
|
|
|
* -rjkaes
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2000-09-12 08:04:42 +08:00
|
|
|
static int add_xtinyproxy_header(struct conn_s *connptr)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2000-09-12 08:04:42 +08:00
|
|
|
char ipaddr[PEER_IP_LENGTH];
|
|
|
|
char xtinyproxy[32];
|
|
|
|
int length;
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
length = snprintf(xtinyproxy, sizeof(xtinyproxy),
|
|
|
|
"X-Tinyproxy: %s\r\n",
|
|
|
|
getpeer_ip(connptr->client_fd, ipaddr));
|
|
|
|
if (safe_write(connptr->server_fd, xtinyproxy, length) < 0)
|
2000-02-17 01:32:49 +08:00
|
|
|
return -1;
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
return 0;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2000-09-12 08:04:42 +08:00
|
|
|
#endif /* XTINYPROXY */
|
2000-02-17 01:32:49 +08:00
|
|
|
|
|
|
|
/*
|
2000-09-12 08:04:42 +08:00
|
|
|
* Here we loop through all the headers the client is sending. If we
|
|
|
|
* are running in anonymous mode, we will _only_ send the headers listed
|
|
|
|
* (plus a few which are required for various methods).
|
|
|
|
* - rjkaes
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2000-09-12 08:04:42 +08:00
|
|
|
static int process_client_headers(struct conn_s *connptr)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2001-09-12 03:26:49 +08:00
|
|
|
char *header;
|
2000-09-12 08:04:42 +08:00
|
|
|
long content_length = -1;
|
|
|
|
|
2001-09-15 03:50:45 +08:00
|
|
|
static char *skipheaders[] = {
|
2000-09-12 08:04:42 +08:00
|
|
|
"proxy-connection",
|
|
|
|
"connection"
|
|
|
|
};
|
|
|
|
int i;
|
|
|
|
|
2001-09-12 03:26:49 +08:00
|
|
|
header = safemalloc(LINE_LENGTH);
|
|
|
|
if (!header)
|
|
|
|
return -1;
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
for ( ; ; ) {
|
2001-08-27 05:11:55 +08:00
|
|
|
if (readline(connptr->client_fd, header, LINE_LENGTH) < 0) {
|
2001-09-12 03:26:49 +08:00
|
|
|
safefree(header);
|
2000-09-12 08:04:42 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
if (header[0] == '\n'
|
|
|
|
|| (header[0] == '\r' && header[1] == '\n')) {
|
|
|
|
break;
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
if (connptr->output_message)
|
|
|
|
continue;
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-15 03:50:45 +08:00
|
|
|
if (!connptr->ssl && strncasecmp(header, "host", 4) ==0)
|
|
|
|
continue;
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
/*
|
|
|
|
* Don't send certain headers.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < (sizeof(skipheaders) / sizeof(char *)); i++) {
|
|
|
|
if (strncasecmp(header, skipheaders[i], strlen(skipheaders[i])) == 0) {
|
|
|
|
break;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
}
|
2000-09-12 08:04:42 +08:00
|
|
|
if (i != (sizeof(skipheaders) / sizeof(char *)))
|
|
|
|
continue;
|
|
|
|
|
2001-09-05 02:22:00 +08:00
|
|
|
if (is_anonymous_enabled() && compare_header(header) < 0)
|
|
|
|
continue;
|
|
|
|
|
2001-08-27 05:11:55 +08:00
|
|
|
if (content_length == -1
|
|
|
|
&& strncasecmp(header, "content-length", 14) == 0) {
|
2000-09-12 08:04:42 +08:00
|
|
|
char *content_ptr = strchr(header, ':') + 1;
|
|
|
|
content_length = atol(content_ptr);
|
|
|
|
}
|
|
|
|
|
2001-09-12 03:26:49 +08:00
|
|
|
if (safe_write(connptr->server_fd, header, strlen(header)) < 0) {
|
|
|
|
safefree(header);
|
2000-09-12 08:04:42 +08:00
|
|
|
return -1;
|
2001-09-12 03:26:49 +08:00
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
if (!connptr->output_message) {
|
|
|
|
#ifdef XTINYPROXY_ENABLE
|
|
|
|
if (config.my_domain
|
|
|
|
&& add_xtinyproxy_header(connptr) < 0) {
|
2001-09-12 03:26:49 +08:00
|
|
|
safefree(header);
|
2000-09-12 08:04:42 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif /* XTINYPROXY */
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
if (safe_write(connptr->server_fd, header, strlen(header)) < 0) {
|
2001-09-12 03:26:49 +08:00
|
|
|
safefree(header);
|
2000-02-17 01:32:49 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-09-12 03:26:49 +08:00
|
|
|
safefree(header);
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
/*
|
|
|
|
* Spin here pulling the data from the client.
|
|
|
|
*/
|
|
|
|
if (content_length >= 0)
|
2001-05-27 10:29:06 +08:00
|
|
|
return pull_client_data(connptr, (unsigned long int)content_length);
|
2000-09-12 08:04:42 +08:00
|
|
|
else
|
|
|
|
return 0;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-09-12 08:04:42 +08:00
|
|
|
* Loop through all the headers (including the response code) from the
|
|
|
|
* server.
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2000-09-12 08:04:42 +08:00
|
|
|
static int process_server_headers(struct conn_s *connptr)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2001-09-12 03:26:49 +08:00
|
|
|
char *header;
|
|
|
|
|
|
|
|
header = safemalloc(LINE_LENGTH);
|
|
|
|
if (!header)
|
|
|
|
return -1;
|
2000-03-12 04:37:44 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
for ( ; ; ) {
|
2001-08-27 05:11:55 +08:00
|
|
|
if (readline(connptr->server_fd, header, LINE_LENGTH) < 0) {
|
2001-09-12 03:26:49 +08:00
|
|
|
safefree(header);
|
2000-09-12 08:04:42 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
if (header[0] == '\n'
|
|
|
|
|| (header[0] == '\r' && header[1] == '\n')) {
|
|
|
|
break;
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
if (!connptr->simple_req
|
|
|
|
&& safe_write(connptr->client_fd, header, strlen(header)) < 0) {
|
2001-09-12 03:26:49 +08:00
|
|
|
safefree(header);
|
2000-09-12 08:04:42 +08:00
|
|
|
return -1;
|
2000-03-12 04:37:44 +08:00
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2000-09-12 08:04:42 +08:00
|
|
|
|
|
|
|
if (!connptr->simple_req
|
|
|
|
&& safe_write(connptr->client_fd, header, strlen(header)) < 0) {
|
2001-09-12 03:26:49 +08:00
|
|
|
safefree(header);
|
2000-09-12 08:04:42 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2001-09-12 03:26:49 +08:00
|
|
|
|
|
|
|
safefree(header);
|
2000-09-12 08:04:42 +08:00
|
|
|
return 0;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
/*
|
|
|
|
* Switch the sockets into nonblocking mode and begin relaying the bytes
|
|
|
|
* between the two connections. We continue to use the buffering code
|
|
|
|
* since we want to be able to buffer a certain amount for slower
|
|
|
|
* connections (as this was the reason why I originally modified
|
|
|
|
* tinyproxy oh so long ago...)
|
|
|
|
* - rjkaes
|
|
|
|
*/
|
|
|
|
static void relay_connection(struct conn_s *connptr)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2000-09-12 08:04:42 +08:00
|
|
|
fd_set rset, wset;
|
|
|
|
struct timeval tv;
|
|
|
|
time_t last_access;
|
|
|
|
int ret;
|
|
|
|
double tdiff;
|
2001-05-27 10:29:06 +08:00
|
|
|
int maxfd = max(connptr->client_fd, connptr->server_fd) + 1;
|
2000-09-12 08:04:42 +08:00
|
|
|
|
|
|
|
socket_nonblocking(connptr->client_fd);
|
|
|
|
socket_nonblocking(connptr->server_fd);
|
|
|
|
|
|
|
|
last_access = time(NULL);
|
|
|
|
|
|
|
|
for ( ; ; ) {
|
|
|
|
FD_ZERO(&rset);
|
|
|
|
FD_ZERO(&wset);
|
|
|
|
|
|
|
|
tv.tv_sec = config.idletimeout - difftime(time(NULL), last_access);
|
|
|
|
tv.tv_usec = 0;
|
|
|
|
|
|
|
|
if (buffer_size(connptr->sbuffer) > 0)
|
|
|
|
FD_SET(connptr->client_fd, &wset);
|
|
|
|
if (buffer_size(connptr->cbuffer) > 0)
|
|
|
|
FD_SET(connptr->server_fd, &wset);
|
|
|
|
if (buffer_size(connptr->sbuffer) < MAXBUFFSIZE)
|
|
|
|
FD_SET(connptr->server_fd, &rset);
|
|
|
|
if (buffer_size(connptr->cbuffer) < MAXBUFFSIZE)
|
|
|
|
FD_SET(connptr->client_fd, &rset);
|
|
|
|
|
2001-05-27 10:29:06 +08:00
|
|
|
ret = select(maxfd, &rset, &wset, NULL, &tv);
|
2001-05-24 01:58:19 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
if (ret == 0) {
|
|
|
|
tdiff = difftime(time(NULL), last_access);
|
|
|
|
if (tdiff > config.idletimeout) {
|
2001-09-07 12:21:07 +08:00
|
|
|
log_message(LOG_INFO, "Idle Timeout (after select) as %g > %u.", tdiff, config.idletimeout);
|
2000-02-17 01:32:49 +08:00
|
|
|
return;
|
2000-09-12 08:04:42 +08:00
|
|
|
} else {
|
|
|
|
continue;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2001-05-27 10:29:06 +08:00
|
|
|
} else if (ret < 0) {
|
2000-09-12 08:04:42 +08:00
|
|
|
return;
|
2001-05-27 10:29:06 +08:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Okay, something was actually selected so mark it.
|
|
|
|
*/
|
|
|
|
last_access = time(NULL);
|
|
|
|
}
|
2001-05-30 23:45:14 +08:00
|
|
|
|
2001-05-27 10:29:06 +08:00
|
|
|
if (FD_ISSET(connptr->server_fd, &rset)
|
|
|
|
&& readbuff(connptr->server_fd, connptr->sbuffer) < 0) {
|
2001-05-30 23:45:14 +08:00
|
|
|
shutdown(connptr->server_fd, SHUT_WR);
|
|
|
|
break;
|
2000-09-12 08:04:42 +08:00
|
|
|
}
|
2001-05-27 10:29:06 +08:00
|
|
|
if (FD_ISSET(connptr->client_fd, &rset)
|
|
|
|
&& readbuff(connptr->client_fd, connptr->cbuffer) < 0) {
|
2001-05-30 23:45:14 +08:00
|
|
|
return;
|
2000-09-12 08:04:42 +08:00
|
|
|
}
|
2001-05-27 10:29:06 +08:00
|
|
|
if (FD_ISSET(connptr->server_fd, &wset)
|
|
|
|
&& writebuff(connptr->server_fd, connptr->cbuffer) < 0) {
|
2001-05-30 23:45:14 +08:00
|
|
|
shutdown(connptr->server_fd, SHUT_WR);
|
|
|
|
break;
|
2000-09-12 08:04:42 +08:00
|
|
|
}
|
2001-05-27 10:29:06 +08:00
|
|
|
if (FD_ISSET(connptr->client_fd, &wset)
|
|
|
|
&& writebuff(connptr->client_fd, connptr->sbuffer) < 0) {
|
2001-05-30 23:45:14 +08:00
|
|
|
return;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
/*
|
|
|
|
* Here the server has closed the connection... write the
|
|
|
|
* remainder to the client and then exit.
|
|
|
|
*/
|
|
|
|
socket_blocking(connptr->client_fd);
|
|
|
|
while (buffer_size(connptr->sbuffer) > 0) {
|
2001-05-27 10:29:06 +08:00
|
|
|
if (writebuff(connptr->client_fd, connptr->sbuffer) < 0)
|
2000-02-17 01:32:49 +08:00
|
|
|
return;
|
|
|
|
}
|
2000-09-12 08:04:42 +08:00
|
|
|
|
|
|
|
return;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
static void initialize_conn(struct conn_s *connptr)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2000-09-12 08:04:42 +08:00
|
|
|
connptr->client_fd = connptr->server_fd = -1;
|
|
|
|
connptr->cbuffer = new_buffer();
|
|
|
|
connptr->sbuffer = new_buffer();
|
|
|
|
|
|
|
|
connptr->output_message = NULL;
|
|
|
|
connptr->simple_req = FALSE;
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
connptr->ssl = FALSE;
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
update_stats(STAT_OPEN);
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
static void destroy_conn(struct conn_s *connptr)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2001-05-30 23:45:14 +08:00
|
|
|
if (connptr->client_fd != -1)
|
|
|
|
close(connptr->client_fd);
|
2000-09-12 08:04:42 +08:00
|
|
|
if (connptr->server_fd != -1)
|
|
|
|
close(connptr->server_fd);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
if (connptr->cbuffer)
|
|
|
|
delete_buffer(connptr->cbuffer);
|
|
|
|
if (connptr->sbuffer)
|
|
|
|
delete_buffer(connptr->sbuffer);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
safefree(connptr->output_message);
|
|
|
|
safefree(connptr);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
update_stats(STAT_CLOSE);
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-09-12 08:04:42 +08:00
|
|
|
* This is the main drive for each connection. As you can tell, for the
|
|
|
|
* first few steps we are using a blocking socket. If you remember the
|
|
|
|
* older tinyproxy code, this use to be a very confusing state machine.
|
|
|
|
* Well, no more! :) The sockets are only switched into nonblocking mode
|
|
|
|
* when we start the relay portion. This makes most of the original
|
|
|
|
* tinyproxy code, which was confusing, redundant. Hail progress.
|
|
|
|
* - rjkaes
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2000-09-12 08:04:42 +08:00
|
|
|
void handle_connection(int fd)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
|
|
|
struct conn_s *connptr;
|
|
|
|
char peer_ipaddr[PEER_IP_LENGTH];
|
2000-09-12 08:04:42 +08:00
|
|
|
char peer_string[PEER_STRING_LENGTH];
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
char *request_line;
|
|
|
|
|
|
|
|
log_message(LOG_CONN, "Connect (file descriptor %d): %s [%s]",
|
|
|
|
fd,
|
2001-08-27 05:11:55 +08:00
|
|
|
getpeer_string(fd, peer_string),
|
|
|
|
getpeer_ip(fd, peer_ipaddr));
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-09 02:58:37 +08:00
|
|
|
connptr = safemalloc(sizeof(struct conn_s));
|
2000-09-12 08:04:42 +08:00
|
|
|
if (!connptr) {
|
2001-09-07 12:21:07 +08:00
|
|
|
log_message(LOG_ERR,
|
|
|
|
"Could not allocate memory for request from [%s]",
|
|
|
|
peer_ipaddr);
|
2000-09-12 08:04:42 +08:00
|
|
|
return;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
initialize_conn(connptr);
|
|
|
|
connptr->client_fd = fd;
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
if (check_acl(fd) <= 0) {
|
|
|
|
update_stats(STAT_DENIED);
|
|
|
|
httperr(connptr, 403, "You do not have authorization for using this service.");
|
|
|
|
goto send_error;
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
#ifdef TUNNEL_SUPPORT
|
|
|
|
/*
|
|
|
|
* If an upstream proxy has been configured then redirect any
|
|
|
|
* connections to it. If we cannot connect to the upstream, see if
|
|
|
|
* we can handle it ourselves. I know I used GOTOs, but it seems to
|
2001-05-27 10:29:06 +08:00
|
|
|
* me to be the best way of handling this situations. So sue me. :)
|
2000-09-12 08:04:42 +08:00
|
|
|
* - rjkaes
|
|
|
|
*/
|
|
|
|
if (config.tunnel_name && config.tunnel_port != -1) {
|
2001-05-27 10:29:06 +08:00
|
|
|
log_message(LOG_INFO, "Redirecting to %s:%d",
|
2000-09-12 08:04:42 +08:00
|
|
|
config.tunnel_name, config.tunnel_port);
|
|
|
|
|
|
|
|
connptr->server_fd = opensock(config.tunnel_name, config.tunnel_port);
|
|
|
|
if (connptr->server_fd < 0) {
|
2001-09-07 12:21:07 +08:00
|
|
|
log_message(LOG_WARNING, "Could not connect to tunnel's end, see if we can handle it ourselves.");
|
2000-09-12 08:04:42 +08:00
|
|
|
goto internal_proxy;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
/*
|
|
|
|
* I know GOTOs are evil, but duplicating the code is even
|
|
|
|
* more evil.
|
|
|
|
* - rjkaes
|
|
|
|
*/
|
|
|
|
goto relay_proxy;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2000-09-12 08:04:42 +08:00
|
|
|
#endif /* TUNNEL_SUPPORT */
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
internal_proxy:
|
2001-09-14 12:56:29 +08:00
|
|
|
request_line = read_request_line(connptr);
|
|
|
|
if (!request_line) {
|
2000-09-12 08:04:42 +08:00
|
|
|
destroy_conn(connptr);
|
|
|
|
return;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
if (process_request(connptr, request_line) < 0) {
|
|
|
|
safefree(request_line);
|
|
|
|
destroy_conn(connptr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
safefree(request_line);
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
send_error:
|
2001-09-15 03:50:45 +08:00
|
|
|
if (!connptr->simple_req) {
|
2000-09-12 08:04:42 +08:00
|
|
|
if (process_client_headers(connptr) < 0) {
|
|
|
|
update_stats(STAT_BADCONN);
|
|
|
|
destroy_conn(connptr);
|
|
|
|
return;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
if (connptr->output_message) {
|
|
|
|
safe_write(connptr->client_fd, connptr->output_message,
|
|
|
|
strlen(connptr->output_message));
|
|
|
|
|
|
|
|
destroy_conn(connptr);
|
|
|
|
return;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
if (!connptr->ssl) {
|
|
|
|
if (process_server_headers(connptr) < 0) {
|
|
|
|
update_stats(STAT_BADCONN);
|
|
|
|
destroy_conn(connptr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (safe_write(connptr->client_fd, "HTTP/1.0 200 Connection established\r\n\r\n", 39) < 0) {
|
|
|
|
log_message(LOG_ERR, "Could not send SSL greeting to client.");
|
|
|
|
destroy_conn(connptr);
|
|
|
|
return;
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
relay_proxy:
|
|
|
|
relay_connection(connptr);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* All done... close everything and go home... :)
|
|
|
|
*/
|
|
|
|
destroy_conn(connptr);
|
|
|
|
return;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|