|
|
|
#include "proxy.h"
|
|
|
|
|
|
|
|
Response *upstreamGetResponse(Request *request){
|
|
|
|
//Here we pretend to be a client
|
|
|
|
|
|
|
|
int client_fd = 0;
|
|
|
|
struct sockaddr_in address;
|
|
|
|
memset( &address, 0, sizeof(address) );
|
|
|
|
struct hostent *host = gethostbyname(request->host);
|
|
|
|
Response *rsp = NULL;
|
|
|
|
|
|
|
|
if ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0){
|
|
|
|
perror("socket failed");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
address.sin_family = AF_INET;
|
|
|
|
address.sin_port = htons( request->port );
|
|
|
|
// We want the request to go out to whatever the host was resolved to
|
|
|
|
memcpy( &address.sin_addr, host->h_addr_list[0], host->h_length );
|
|
|
|
|
|
|
|
if((connect(client_fd, (struct sockaddr *)&address, sizeof(address)))<0) {
|
|
|
|
perror("connect failed");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *toSend = requestToString(request);
|
|
|
|
|
|
|
|
if ( write( client_fd, toSend, strlen(toSend) ) != strlen(toSend) ){
|
|
|
|
perror( "Write Error" );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rsp = newResponseFromSocket( client_fd );
|
|
|
|
|
|
|
|
return rsp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sendConnectionEstablished(int client){
|
|
|
|
// If it is a connect request, we are dealing with https
|
|
|
|
|
|
|
|
// I am basically doing the same thing that mitmproxy does here
|
|
|
|
// We start by responding with 200 Connection Established which
|
|
|
|
// in a normal proxy would mean that we have established a
|
|
|
|
// connection with the remote host. However, we haven't because we
|
|
|
|
// are going to pretend to be the host to the client and pretend to
|
|
|
|
// be the client to the host
|
|
|
|
|
|
|
|
Response *response = newResponse();
|
|
|
|
connectionEstablished(response);
|
|
|
|
char *responseStr = responseToString(response);
|
|
|
|
send(client , responseStr, strlen(responseStr) , 0 );
|
|
|
|
freeResponse( response );
|
|
|
|
}
|
|
|
|
|
|
|
|
void proxyRequest(Request *request, int client, CertificateAutority *ca){
|
|
|
|
if ( strcmp( request->method, "CONNECT" ) == 0 ){
|
|
|
|
|
|
|
|
sendConnectionEstablished(client);
|
|
|
|
|
|
|
|
// All we might need from the connect resquest is the host
|
|
|
|
char *host = request->host;
|
|
|
|
freeRequest( request );
|
|
|
|
|
|
|
|
// If we already have a host cert for the domain we're dealing with use
|
|
|
|
// it
|
|
|
|
CertList *certItem = findCertListItem( ca->certs, host );
|
|
|
|
if ( certItem == NULL ){
|
|
|
|
// If we don't, generate a new one
|
|
|
|
X509 *siteCert = generate_site_cert( ca->pkey, ca->cert, host );
|
|
|
|
certItem = newCertListItem( host, ca->pkey, siteCert );
|
|
|
|
if ( ca->certs == NULL ) ca->certs = certItem;
|
|
|
|
else getLastCertListItem(ca->certs)->next = certItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SSL_CTX *ctx;
|
|
|
|
SSL *ssl;
|
|
|
|
char buf[1024] = {0};
|
|
|
|
int bytes;
|
|
|
|
Response *response;
|
|
|
|
|
|
|
|
SSL_library_init();
|
|
|
|
|
|
|
|
ctx = setup_ctx(certItem);
|
|
|
|
|
|
|
|
ssl = SSL_new(ctx);
|
|
|
|
SSL_set_fd( ssl, client );
|
|
|
|
|
|
|
|
if ( SSL_accept(ssl) == -1 ){
|
|
|
|
ERR_print_errors_fp(stderr);
|
|
|
|
} else {
|
|
|
|
bytes = SSL_read(ssl, buf, sizeof(buf));
|
|
|
|
buf[bytes] = '\0';
|
|
|
|
request = newRequestFromString( buf );
|
|
|
|
//If this request doesn't contain a host, use the one from the
|
|
|
|
//connect request
|
|
|
|
if ( strlen( request->host ) == 0 ){
|
|
|
|
free(request->host);
|
|
|
|
request->host = strdup( host );
|
|
|
|
}
|
|
|
|
response = upstreamGetResponse(request);
|
|
|
|
char *responseStr = responseToString( response );
|
|
|
|
SSL_write( ssl, responseStr, strlen(responseStr) );
|
|
|
|
}
|
|
|
|
SSL_free(ssl);
|
|
|
|
SSL_CTX_free(ctx);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
Response *response = upstreamGetResponse(request);
|
|
|
|
char *responseStr = responseToString( response );
|
|
|
|
send(client , responseStr, strlen(responseStr) , 0 );
|
|
|
|
free( responseStr );
|
|
|
|
freeResponse( response );
|
|
|
|
}
|
|
|
|
}
|