информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Spanning Tree Protocol: недокументированное применениеВсе любят мед
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Три миллиона электронных замков... 
 Doom на газонокосилках 
 Умер Никлаус Вирт 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
Я реализовал этот алгоритм, и он работает, но почему-то... 26.01.09 08:24  Число просмотров: 2146
Автор: Vedrus <Serokhvostov Anton> Статус: Member
Отредактировано 26.01.09 08:27  Количество правок: 2
<"чистая" ссылка> <обсуждение закрыто>
Я реализовал этот алгоритм, и он работает, но почему-то клиент не получает данных от сервера. Когда я устанавливал в качестве локального PROXY-сервера Paros всё работало.

Вот обрезанная версия моего кода (без проверки ошибок):
#include <windows.h>

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

#define MAX_CLIENTS	100
#define BUF_SIZE	65535

#define PORT_PROXY_SERVER	7500
#define PORT_GAME_SERVER	80

void main()
{
	WSADATA WSAStartData;			// Структура данных библиотеки сокетов

	struct sockaddr_in ProxyServerSAddr;
	struct sockaddr_in GameServerSAddr;

	char szBuf[BUF_SIZE];
	char GameServerIP[] = "88.212.221.133";
	SOCKET sockProxyServer;			// Сокет нашего прокси
	SOCKET sockGameServer;			// Сокет игрового сервера
	SOCKET sockGameClient;			// Сокет игрового клиента
	DWORD dwBytesTransfered;

	WSAStartup(MAKEWORD(1, 1), &WSAStartData);

	// Запустить PROXY-сервер	 //
	sockProxyServer = socket(AF_INET, SOCK_STREAM, 0);
	ProxyServerSAddr.sin_family = AF_INET;
	ProxyServerSAddr.sin_addr.s_addr =htonl(INADDR_ANY);
	ProxyServerSAddr.sin_port = htons(PORT_PROXY_SERVER);
	bind(sockProxyServer, (struct sockaddr *) &ProxyServerSAddr, sizeof (ProxyServerSAddr));
	listen(sockProxyServer, MAX_CLIENTS);
	// Дождаться подключения клиента //
	sockGameClient = accept(sockProxyServer, NULL, NULL);

	// Подключиться к серверу игры //
	sockGameServer = socket(AF_INET, SOCK_STREAM, 0);
	GameServerSAddr.sin_family = AF_INET;
	GameServerSAddr.sin_addr.s_addr = inet_addr(GameServerIP);
	GameServerSAddr.sin_port = htons(PORT_GAME_SERVER);
	connect(sockGameServer, (struct sockaddr *) &GameServerSAddr, sizeof(GameServerSAddr));

	while (1)
	{
		// Получить пакет от клиента	//
		dwBytesTransfered = recv(sockGameClient, szBuf, BUF_SIZE, 0);
		// Передать пакет серверу		//
		dwBytesTransfered = send(sockGameServer, szBuf, dwBytesTransfered, 0);
		// Получить пакет от сервера	//
		dwBytesTransfered = recv(sockGameServer, szBuf, BUF_SIZE, 0);
		// Передать пакет клиенту		//
		dwBytesTransfered = send(sockGameClient, szBuf, dwBytesTransfered, 0);
	}
}

---
<programming>
[win32] алгоритм локального proxy-сервера 26.01.09 03:49   [Ustin]
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
Проверьте, пожалуйста, правильно ли я мыслю.

Локальный PROXY я создаю для перехвата (в целях просмотра) TCP-трафика приложения, которое умеет работать через PROXY-сервер. Вот мой алгоритм:
1. Создать прослушивающий сокет.
2. Ждать соединения клиента.
3. Прочитать пакет переданный клиентом.
4. Передать пакет серверу.
5. Ждать ответа от сервера.
6. Читать пакет сервера.
7. Передать пакет клиенту.
8. Повторять п.3-7 пока соединение открыто.
9. Закрыть сокеты.
10. Конец.
Я реализовал этот алгоритм, и он работает, но почему-то... 26.01.09 08:24  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
Отредактировано 26.01.09 08:27  Количество правок: 2
<"чистая" ссылка> <обсуждение закрыто>
Я реализовал этот алгоритм, и он работает, но почему-то клиент не получает данных от сервера. Когда я устанавливал в качестве локального PROXY-сервера Paros всё работало.

Вот обрезанная версия моего кода (без проверки ошибок):
#include <windows.h>

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

#define MAX_CLIENTS	100
#define BUF_SIZE	65535

#define PORT_PROXY_SERVER	7500
#define PORT_GAME_SERVER	80

void main()
{
	WSADATA WSAStartData;			// Структура данных библиотеки сокетов

	struct sockaddr_in ProxyServerSAddr;
	struct sockaddr_in GameServerSAddr;

	char szBuf[BUF_SIZE];
	char GameServerIP[] = "88.212.221.133";
	SOCKET sockProxyServer;			// Сокет нашего прокси
	SOCKET sockGameServer;			// Сокет игрового сервера
	SOCKET sockGameClient;			// Сокет игрового клиента
	DWORD dwBytesTransfered;

	WSAStartup(MAKEWORD(1, 1), &WSAStartData);

	// Запустить PROXY-сервер	 //
	sockProxyServer = socket(AF_INET, SOCK_STREAM, 0);
	ProxyServerSAddr.sin_family = AF_INET;
	ProxyServerSAddr.sin_addr.s_addr =htonl(INADDR_ANY);
	ProxyServerSAddr.sin_port = htons(PORT_PROXY_SERVER);
	bind(sockProxyServer, (struct sockaddr *) &ProxyServerSAddr, sizeof (ProxyServerSAddr));
	listen(sockProxyServer, MAX_CLIENTS);
	// Дождаться подключения клиента //
	sockGameClient = accept(sockProxyServer, NULL, NULL);

	// Подключиться к серверу игры //
	sockGameServer = socket(AF_INET, SOCK_STREAM, 0);
	GameServerSAddr.sin_family = AF_INET;
	GameServerSAddr.sin_addr.s_addr = inet_addr(GameServerIP);
	GameServerSAddr.sin_port = htons(PORT_GAME_SERVER);
	connect(sockGameServer, (struct sockaddr *) &GameServerSAddr, sizeof(GameServerSAddr));

	while (1)
	{
		// Получить пакет от клиента	//
		dwBytesTransfered = recv(sockGameClient, szBuf, BUF_SIZE, 0);
		// Передать пакет серверу		//
		dwBytesTransfered = send(sockGameServer, szBuf, dwBytesTransfered, 0);
		// Получить пакет от сервера	//
		dwBytesTransfered = recv(sockGameServer, szBuf, BUF_SIZE, 0);
		// Передать пакет клиенту		//
		dwBytesTransfered = send(sockGameClient, szBuf, dwBytesTransfered, 0);
	}
}

---
Как вариант 26.01.09 18:17  
Автор: PS <PS> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
> Вот обрезанная версия моего кода (без проверки ошибок):
>
> 	while (1)
> 	{
> 		// Получить пакет от клиента	//
> 		dwBytesTransfered = recv(sockGameClient,
> szBuf, BUF_SIZE, 0);
> 		// Передать пакет серверу		//
> 		dwBytesTransfered = send(sockGameServer,
> szBuf, dwBytesTransfered, 0);
> 		// Получить пакет от сервера	//
> 		dwBytesTransfered = recv(sockGameServer,
> szBuf, BUF_SIZE, 0);
> 		// Передать пакет клиенту		//
> 		dwBytesTransfered = send(sockGameClient,
> szBuf, dwBytesTransfered, 0);
> 	}
> 

---

Без прокси: Игра передет пакет AAABBBCCC, сервер получает два пакета AAAB и BBCCC, разбирает сообщение, и отвечает BBB.

С твоей реализацией: Игра передает пакет AAABBBCCC, прокси ловит AAAB, и передает серверу; останавливается и ждет ответа. Сервер получает AAAB и ждет завершения сообщения.
Клиент ждет, прокси ждет, сервер ждет. Ляпота...
Фрагметнация пакета - это следующая задача. Но сейчас даже... 26.01.09 19:11  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
Фрагметнация пакета - это следующая задача. Но сейчас даже на полностью переданных пакетах омй прокси не работает. Ты констатировал проблему, а альтернативный вариант для много обещающего заголовка "как вариант"?
Альтернативный вариант тебе подскажет серое вещество. Если... 27.01.09 15:42  
Автор: PS <PS> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
> Фрагметнация пакета - это следующая задача. Но сейчас даже
> на полностью переданных пакетах омй прокси не работает. Ты
> констатировал проблему, а альтернативный вариант для много
> обещающего заголовка "как вариант"?

Альтернативный вариант тебе подскажет серое вещество. Если блокирующие вызовы могут привести к проблеме, значит надо использовать не блокирующую архитектуру. Как именно - сам додумаешься.

Если на полностью полученных пакетах не работает, то 1. Врубай сниффер без прокси и смотри что идет.
2. В прокси логируй все что пришло, и что ушло. 3. Проснифь с прокси.
Проанализируй разницу и найди решение :)
Спасибо, попробую 27.01.09 18:51  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
PS, я проделал описанную тобой процедуру. В... 28.01.09 13:36  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
PS, я проделал описанную тобой процедуру. В результате убедился, что первый запрос от клиента к серверу одинаков и с прокси и без; ответ сервера на этот запрос также одинаков с прокси и без.

Далее, мой прокси перестаёт получать и передавать данные, вместо этого при обращении к функциям передачи возвращает нулевую длинну. GetLastError и WSAGetLastError при этом ошибок не возвращают.

Если перенести строку
"sockGameClient = accept(sockProxyServer, NULL, NULL);"
в начало цикла, то дело доходит до следующего запроса. Этот запрос успешно читается от клиента. При попытке передать этот запрос серверу (send) ошибки не выдаётся, но до снифера этот пакет не доходит. При последующем вызове recv выдаётся ошибка 10053 (Программа на вашем хость компьютере разорвала установленное подключение).

Я подозреваю, что эта проблема связана с необходимостью определённым образом использовать функции accept и connect, но как именно понять не могу.
А где спасибо ? :) 28.01.09 15:41  
Автор: PS <PS> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
> PS, я проделал описанную тобой
> процедуру. В результате убедился, что первый запрос от
> клиента к серверу одинаков и с прокси и без; ответ сервера
> на этот запрос также одинаков с прокси и без.
>
> Далее, мой прокси перестаёт получать и передавать данные,
> вместо этого при обращении к функциям передачи возвращает
> нулевую длинну. GetLastError и WSAGetLastError при этом
> ошибок не возвращают.
>
> Если перенести строку
> "sockGameClient = accept(sockProxyServer, NULL, NULL);"
> в начало цикла, то дело доходит до следующего запроса. Этот
> запрос успешно читается от клиента. При попытке передать
> этот запрос серверу (send) ошибки не выдаётся, но до
> снифера этот пакет не доходит. При последующем вызове recv
> выдаётся ошибка 10053 (Программа на вашем хость компьютере
> разорвала установленное подключение).
>
> Я подозреваю, что эта проблема связана с необходимостью
> определённым образом использовать функции accept и connect,
> но как именно понять не могу.

Для умного:
MSDN
If no error occurs, recv returns the number of bytes received. If the connection has been gracefully closed, the return value is zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError.

Для не очень умного:
У тебя соединение разорвано

Для тупого:
Скорей всего твой клиент после получения ответа откоонективается от сервера, а для нового запроса - подрубается.

Совсем для тупого:
Обрабатывай дисконнект от клиента (да и от сервера тоже).

А есть ещё пункт после "Совсем для тупого"? Каким образом... 28.01.09 16:06  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
Отредактировано 28.01.09 16:15  Количество правок: 1
<"чистая" ссылка> <обсуждение закрыто>
А есть ещё пункт после "Совсем для тупого"? Каким образом это обработать? В предыдущем посте я именно это и спросил. Плюс ко всему, я тоже предположил, что клиент отконнекчивается, поэтому воткнул accept в цикл, в конце цикла ставлю closesocket и shutdown.

Но проблема в том, что касяк наблюдается не на связке прокси-клиент, а на связки прокси-сервер. Вот собственно код:
	while (1)
	{
		sockGameClient = accept(sockProxyServer, NULL, NULL);

		// Получить пакет от клиента	//
		dwBytesTransfered = recv(sockGameClient, szBuf, BUF_SIZE, 0);
		// Передать пакет серверу		//
		dwBytesTransfered = send(sockGameServer, szBuf, dwBytesTransfered, 0);
		// Получить пакет от сервера	//
		dwBytesTransfered = recv(sockGameServer, szBuf, BUF_SIZE, 0);
		// Передать пакет клиенту		//
		dwBytesTransfered = send(sockGameClient, szBuf, dwBytesTransfered, 0);

		shutdown(sockGameClient, 2);
		closesocket(sockGameClient);
	}

---
Это все от лени у тебя 28.01.09 16:31  
Автор: PS <PS> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
что бы разобраться надо подумать.

для категорично тупого:
Варианты использования клиент серверных приложений:
1. Перзистент коннект: клиент коннектиться к серверу и они держат соединение до второго пришествия - под этот вариант и была заточена реализация твоего прокси.
2. Типа Web коннект: один (любой!) из участников, после обмена сообщениями рвет соединение.

Сейчас ты обработал отвал клиента, но забыл, что и сервер может разорвать такое соединение.

Тупое решение для ленивого программера: Затачивать прокси под конкретных участников. В твоем случае в начало цикла ставить акцеп, после акцепта коннект к серверу. сенд-рецив-сенд, и закрытие обоих сокетов.

Нормальное решение: предложено в этой ветке чуть раньше. + твоя голова.
Если соединение разорвано - восстановить его с помощью connect для клиента или accept и ждать для сервера. А ещё можно для каждого сокета создавать отдельную нитку, в которой делать (connect; while not error do (recv;processdata)) - это решит все проблемы 28.01.09 16:13  
Автор: Ustin <Ustin> Статус: Elderman
Отредактировано 28.01.09 16:22  Количество правок: 2
<"чистая" ссылка> <обсуждение закрыто>
или (для слушающего сокета):
while not terminated do
(
bind; listen;
while not listenererror do forknewthread(accept)
)
- типа того, и работать с полученным в результате акцепта сокетом также как с клиентским
Ты имеешь в виду Fiber? 29.01.09 12:42  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
Ты имеешь в виду Fiber?
А как тогда определить, что recv передала все данные? В случае с HTTP можно читать переменную content-length, а в общем случае как быть?
Тебе не нужно определять длинны :) 29.01.09 15:13  
Автор: PS <PS> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
> Ты имеешь в виду Fiber?
> А как тогда определить, что recv передала все данные? В
> случае с HTTP можно читать переменную content-length, а в
> общем случае как быть?

Тебе не нужно определять длинны :)
Тебе нужно получать данные и отсылать их на другое плечо до тех пор, пока соединение не разорвано.
Как только на одном из плечей коннекшен клозед - закрываешь другое плечо.
Ты прелагаешь вызывать recv, пока соединение не оборвётся? Я... 29.01.09 15:40  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
Ты прелагаешь вызывать recv, пока соединение не оборвётся? Я так пробовал - когда данные передались, а я вызываю ещё один recv, то происходит ЗАВИСАНИЕ.
RTFM: If no incoming data is available at the socket, the recv call waits for data to arrive unless the socket is nonblocking 29.01.09 16:55  
Автор: Ustin <Ustin> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
Прочитай хотя-бы главу MSDN "Windows Sockets 2 Application Program Interface" прежде чем классифицировать нормальную работу как ЗАВИСАНИЕ, да ещё и с большой буквы
И попробуй заюзать-таки indy port-mapper - он решает твою задачу в одно движение, + 2 движения - ты меняешь данные на лету
Ты имеешь в виду easy port mapper? 29.01.09 18:05  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
Ты имеешь в виду easy port mapper?

PS. Я знаю, что это вполне штатная ситуация, предыдущий пост был сделан с целью показать, что идея PS'а в моём случае не сработает.
нет, я имею ввиду компонент, входящий в дефолтную поставку Borland Delphi и C++Builderа 29.01.09 18:31  
Автор: Ustin <Ustin> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
> Ты имеешь в виду easy port mapper?
subj
> PS. Я знаю, что это вполне штатная ситуация, предыдущий
> пост был сделан с целью показать, что идея
> PS'а в моём случае не сработает.
бред, его идея работает. Единственное - её проблематично реализовать в контексте одного потока (как, собсно, и вообще работу с блокирующими сокетами, исключая вырожденные случаи).
Я не зря предлагаю использовать готовый компонент - там реализованы обходы кучи стандартных грабель типа междупоточной синхронизации, на которые есть все шансы наступить сообщений этак через 5, когда к многопоточности ты таки придёшь.
А ещё игруха может закончиться :)
Всё уже придумано до нас (цэ)
2 Ustin 30.01.09 15:38  
Автор: PS <PS> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
> бред, его идея работает. Единственное - её проблематично
> реализовать в контексте одного потока (как, собсно, и
> вообще работу с блокирующими сокетами, исключая вырожденные
> случаи).

вообще-то select спасает отца русской демократии в одном потоке :) Никакой проблематичности не вызывает ни одно поточное, ни много поточная реализация. Хотя многопоточность, конечно, удобней. Особенно, если потоки создавать не win api, а с помощью boost. А еще можно использовать boost::asio - вообще конфетка. Но, самый шик - реализовать это дело на C#, используя вместо System.Threading.Thread ассинхронные делегаты. А вот самый большой изъеб, сделать то же самое с помощью WCF, причем на C++/CLI

Это я все над Вердусом издеваюсь :)
Издёвка удалась, ещё технологий добавил, и вообще меня в... 01.02.09 19:12  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
Издёвка удалась, ещё технологий добавил, и вообще меня в этом деле закопал. Я нашёл ещё один пример прокси, сейчас разбираюсь с ним.
Попользовал я этот компонент. Всё работает на ура. Но... 30.01.09 09:06  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
Отредактировано 30.01.09 09:07  Количество правок: 1
<"чистая" ссылка> <обсуждение закрыто>
Попользовал я этот компонент. Всё работает на ура. Но хотелось бы на боле низком уровне с этой задачей разобраться. Я нашёл 2 примера в сети - исходники socks4 proxy на дельфи и ещё нв асинхронных сокетах на C++ пример.

Первый пример не рабочий, а второй тормозит передачу данных. Может кто-нибудь поделится ссылкой на какой-нибудь другой простой прокси?

Прокси на C++
1  |  2 >>  »  




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach