/**************************************************************************
SILENT HTTP PROXY
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 3 of the License, 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.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Coded By Matrix86 ----> matrix86 {AT} tuxmealux {DOT} net
http://www.tuxmealux.net
(Thx to Evilsocket for his advice)
****************************************************************************/
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <pthread.h>
#include <time.h>
#define LISTENPORT 8080
#define HTTPPORT 80
#define BACKLOG 10
#define VERSION "0.1 alpha"
#define AUTHOR "Matrix86"
#define SITE "http://www.tuxmealux.net"
int shp_exit = 1;
FILE *logfile = NULL;
FILE *logpkt = NULL;
int view = 0;
int dm = 0;
typedef struct context {
int sock;
struct sockaddr_in client;
char req[BUFSIZ];
} shp_context;
void shp_banner(){
printf("*****************************************\n");
printf("* HTTP SILENT PROXY *\n");
printf("* VERSION: %s *\n",VERSION
);
printf("* Author: %s *\n",AUTHOR
);
printf("* Site: %s *\n",SITE
);
printf("*****************************************\n\n");
}
void shp_usage( char * ex){
printf( "Usage : %s <options>\n", ex
);
printf( "\t\t-o <namefile> : write on logfile only http request\n" );
printf( "\t\t-p <namefile> : write on another logfile request and packet\n" );
printf( "\t\t-v : realtime view http packet.\n\n" );
printf( "\t\t-d : daemon mode.\n\n" );
}
void shp_die( char *ms )
{
fprintf( stdout, "[ERROR] %s\n", ms );
exit( 1 );
}
void shp_quit( int sig ){
shp_exit = 0;
}
void set_timeout( int sd ){
int y = 1;
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
setsockopt( sd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval) );
setsockopt( sd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval) );
setsockopt( sd, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(int) );
}
int shp_connection( char *address, int port )
{
int sock;
struct sockaddr_in host;
struct hostent *data;
char ip[INET6_ADDRSTRLEN];
if ((sock = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
{
printf( "[WARNING] Failed to create socket." );
return -1;
}
memset( (void *) &host, 0, sizeof( host ) );
host.sin_family = AF_INET;
host.sin_port = htons( port );
if ( ( data = gethostbyname( address ) ) == NULL ) return -1;
inet_ntop( data->h_addrtype, data->h_addr, ip, sizeof( ip ) );
host.sin_addr.s_addr = inet_addr( ip );
if( connect ( sock, (struct sockaddr *) &host, sizeof( struct sockaddr ) ) < 0 )
{
return -1;
}
set_timeout( sock );
return sock;
}
void showpkt( char * pkt ) {
char *p;
p = pkt;
while( *p != '\0' ){
else if(*p ==
'\n') printf("\\n\n");
p++;
}
return;
}
int shp_forge_pkt( char * pkt, shp_context * ctx ){
char *p1, *p2, *end;
int offset;
// Extract only first line from http request
if( ( offset = (int) strpbrk( pkt, "\r\n" ) ) ){
offset -= (int) pkt;
strncpy( ctx->req, pkt, offset );
}
ctx->req[offset] = '\0';
if( ( p2 = strstr( ctx->req, "http://" ) ) != NULL ){
p1 = ( p2 - ctx->req ) + pkt + strlen( "http://" );
while( *p1 != '/' ) p1++;
end = strstr( pkt, "\r\n\r\n" );
end += strlen( "\r\n\r\n" );
while( p1 != end ){
*p2 = *p1;
p1++;
p2++;
}
*p2 = *p1;
return 0;
}
else return 1;
}
void shp_pipeline ( shp_context * ctx ) {
char *p, *p1, host[BUFSIZ] = { 0 }, buffer[BUFSIZ] = { 0 }, timebuf[BUFSIZ] = { 0 };
int outsock, mslen;
time_t curtime = time( NULL );
struct tm *loctime;
loctime = localtime (&curtime);
strftime (timebuf, BUFSIZ, "[ %d/%m/%y %H:%M ]", loctime);
if( ( p = strstr( ctx->req, "Host: " ) ) != NULL ) {
p += strlen( "Host: " );
p1 = host;
while( *p != '\r' && *( p + 1 ) != '\n' ) {
*p1 = *p;
p1++;
p++;
}
if( dm ) fprintf (stdout, "%s HTTP request from: %s to: %s\n", timebuf, inet_ntoa (ctx->client.sin_addr), host);
if( logpkt != NULL ) {
fprintf (logpkt, "%s HTTP request from: %s to: %s\n", timebuf, inet_ntoa (ctx->client.sin_addr), host);
fprintf (logpkt, "%s\n",ctx->req);
}
if( view && dm ) showpkt( ctx->req );
if( logfile != NULL ) fprintf (logfile, "%s HTTP request from: %s to: %s\n", timebuf, inet_ntoa (ctx->client.sin_addr), host);
if ( ( outsock = shp_connection( host, HTTPPORT ) ) < 0 ){
if( dm ) fprintf( stdout, "Impossible to connect to host %s\n", host );
}
else {
write( outsock, ctx->req, strlen( ctx->req ) );
while( ( mslen = read( outsock, buffer, BUFSIZ ) ) > 0 ) {
write ( ctx->sock, buffer, mslen );
memset( buffer, 0, BUFSIZ );
}
close( outsock );
}
}
return;
}
void * shp_req_manage( void * context ) {
shp_context *ctx = (shp_context *) context;
char buffer[BUFSIZ] = { 0 };
int mslen;
if( ( mslen = read ( ctx->sock, buffer, BUFSIZ ) ) < 0 ){
free( ctx );
shp_die( "Problem with read function." );
}
if( shp_forge_pkt( buffer, ctx ) == 0 ) {
shp_pipeline( ctx );
} else {
strncpy( ctx->req, buffer, BUFSIZ );
shp_pipeline( ctx );
}
close( ctx->sock );
free( ctx );
pthread_exit(NULL);
}
int main( int argc, char *argv[] ){
struct sockaddr_in si;
struct sockaddr_in client;
struct timeval tv;
int sock1, in_con, c;
while( ( c = getopt( argc, argv, "dvo:p:" ) ) != -1 ){
switch(c){
case 'o' : logfile = fopen( optarg, "a+" ); break;
case 'p' : logpkt = fopen( optarg, "a+" ); break;
case 'v' : view = 1; break;
case 'd' : dm = 1; break;
default :
shp_usage(strdup(argv[0]));
return -1;
}
}
if( dm ) daemon(1,0);
signal( SIGINT, shp_quit );
signal( SIGKILL, shp_quit );
sock1 = socket( AF_INET, SOCK_STREAM, 0 );
if ( sock1 < 0 ) shp_die( "Failed to create socket." );
tv.tv_sec = 2;
tv.tv_usec = 0;
set_timeout( sock1 );
memset( (void *) &si, 0, sizeof( si ) );
si.sin_family = AF_INET;
si.sin_port = htons ( LISTENPORT );
si.sin_addr.s_addr = htonl ( INADDR_ANY );
if( bind ( sock1, (struct sockaddr *) &si, sizeof ( si ) ) < 0 )
{
close ( sock1 );
shp_die( "Binding socket." );
}
if( listen ( sock1, BACKLOG ) < 0 )
{
close ( sock1 );
shp_die( "Could not listen on socket." );
}
shp_banner();
if( dm ) fprintf( stdout, "Press CTRL-C to exit.\n" );
while( shp_exit ){
socklen_t addrlen = sizeof( client );
while ( ( in_con = accept( sock1, (struct sockaddr *) &client, &addrlen ) ) < 0 && ( errno == EINTR ) );
if( in_con > 0 ){
//printf( "Http request.\n" );
set_timeout( in_con );
pthread_t thread;
shp_context *context;
context = (shp_context *) calloc( sizeof(shp_context), 1 );
context->sock = in_con;
context->client = client;
pthread_create( &thread, 0, shp_req_manage, (void *) context );
}
}
if( logpkt != NULL ) fclose(logpkt);
if( logfile != NULL ) fclose(logfile);
if( dm
) printf( "Power off.\n" );
fflush(stdout);
close( sock1 );
return 0;
}