#include #include #include #include #include #ifdef _WIN32 #include #include #else #include #include #include #include #include #include #include #include #include #include #include #include #include #endif #include "bnc.h" #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; #ifndef _WIN32 struct sigaction sact; #else WSADATA wData; int j; int k; #endif initialise_options(); 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); } #ifdef LINUX if(strlen(options.cloak_name) != 0) { memset(argv[0], 0, strlen(argv[0])); strncpy(argv[0], options.cloak_name, strlen(options.cloak_name)); for(i = 1; i < argc; i++) { memset(argv[i], 0, strlen(argv[i])); } } #endif 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, "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)b) << 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, "401 Authorization Required\r\n"); strcat(buffer, "

Authorization Required

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.

\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, "Bouncer Admin

Bouncer Admin 0.1 (Beta 1)
Copyright © 2001 Chris Mason

\r\n"); snprintf(sbuffer, sizeof(sbuffer), "

Bouncer Uptime: %s
Total Connections: %ld
Total Data Throughput: %s KB

\r\n", format_time(time(NULL) - init_time), connections, format_float(total_data / 1024.0)); strcat(buffer, sbuffer); strcat(buffer, "

List Connections
Shutdown Bouncer

\r\n"); strcat(buffer, "\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, "Bouncer Admin

Bouncer Admin 0.1 (Beta 1)
Copyright © 2001 Chris Mason

\r\n

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

"); if(!socks5) { snprintf(sbuffer, sizeof(sbuffer), "Destination Host: %s
", 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, "

"); } if(socks5) { strcat(buffer, ""); } else { strcat(buffer, "
SlotStatusSourceDestinationTime ConnectedData Transferred
"); } 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, "
SlotStatusSourceTime ConnectedData Transferred

Back\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, "Bouncer Admin

Bouncer Admin 0.1 (Beta 1)
Copyright © 2001 Chris Mason

\r\n"); strcat(buffer, "

Bouncer Successfully Shutdown

\r\n"); strcat(buffer, "\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)); }