Faost
13.06.2010, 20:59
Т.к. в моей пред.теме о socks никто ничем помочь не смог, создаю еще одну.
Проблема заключается в некорректности работы сокс-сервера через соксификаторы.
Для наглядности, чтоб было максимально понятно написал простейший socks4 сервер с подробнейшими комментариями (Delphi, WinSock + WinApi).
Качаем соксификатор (http://www.freecap.ru/?p=download), настраиваем в нем socks4 (Сервер: 127.0.0.1, порт: 8080).
Качаем исходник socks4-сервера (http://www.sendspace.com/file/ehy83w) (залил для большей наглядности)
Компилируем, запускаем, заходим на mail.ru - страница грузится очень долго (конца загрузки дождаться мне так и не удалось), хотя тот же гугл, да и вконтакт (по крайней мере на "Поиске людей") работают норм.
Так вот, нужна подсказка, из-за чего это происходит и как это исправить.
Код:
program Socks4;
uses
Windows,
WinSock;
const IpToListen = '127.0.0.1';
function OurBrowserListening(p: pointer): DWORD; stdcall;
var BSock: TSocket;
vn, cd, UserID: byte;
answer: array[1..8] of byte;
buf: pointer;
addr: sockaddr_in;
TargetSock: TSocket;
fset: tfdset;
i: integer;
avail_bytes: integer;
time_out: timeval;
label 2, 3;
begin
BSock:= Cardinal(p); //BSock - браузер (подключеный клиент)
TargetSock:= socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
//TargetSock - таргет (цель, конечный хост)
if TargetSock = INVALID_SOCKET then ExitThread(0);
ZeroMemory(@addr, sizeof(addr));
addr.sin_family:= PF_INET;
//Теперь нужно принять данные от браузера (клиента):
// +----+----+----+----+----+----+----+----+----+----+....+----+
// | VN | CD | DSTPORT | DSTIP | USERID |NULL|
// +----+----+----+----+----+----+----+----+----+----+....+----+
// 1 1 2 4 variable 1
recv(BSock, vn, sizeof(vn), 0); //принимаем версию socks - 4
recv(BSock, cd, sizeof(cd), 0); //принимаем команду - 1 (connect)
if cd <> $01 then goto 2; //если не connect, то перейти к метке 2
recv(BSock, addr.sin_port, 2, 0); //принимаем порт таргета (цели)
recv(BSock, addr.sin_addr.S_addr, 4, 0); //принимаем ip таргета (цели)
repeat
recv(BSock, UserID, sizeof(UserID), 0);
until UserID = $00; //принимаем UserID, оканчивающийся NULL-байтом
//пытаемся соединиться с таргетом
if connect(TargetSock, addr, sizeof(addr)) <> 0 then
begin //если не удалось, то:
2:ZeroMemory(@answer, sizeof(answer));
answer[1]:= $00; //должен быть 0
answer[2]:= $5B; //$5B - ошибка
send(BSock, answer, sizeof(answer), 0); //посылаем ответ браузеру (клиенту)
goto 3;
end;
//Теперь нужно послать ответ браузеру (клиенту)
// +----+----+----+----+----+----+----+----+
// | VN | CD | DSTPORT | DSTIP |
// +----+----+----+----+----+----+----+----+
// 1 1 2 4
ZeroMemory(@answer, sizeof(answer));
answer[1]:= $00; //должен быть 0
answer[2]:= $5A; //$5A - коннект к таргету успешен
send(BSock, answer, sizeof(answer), 0); //посылаем ответ браузеру (клиенту)
//Теперь следует непосредственно перенаправление данных от браузера к
//таргету и наоборот
while true do
begin //while true do
FD_ZERO(fset);
FD_SET(BSock, fset);
FD_SET(TargetSock, fset);
time_out.tv_sec:= 8; //установим таймаут на select в 8 секунд
time_out.tv_usec:= 0;
if select(0, @fset, nil, nil, @time_out) <= 0 then
goto 3;
//если есть данные от браузера и/или таргета, то:
if FD_IsSet(BSock, fset) then //если есть данные от браузера, то:
begin
avail_bytes:= 0;
ioctlsocket(BSock, FIONREAD, avail_bytes); //читаем кол-во пришедших байт
buf:= VirtualAlloc(nil, avail_bytes, MEM_COMMIT, PAGE_READWRITE); //освобождаем под них память
i:= recv(BSock, buf^, avail_bytes, 0); //принимаем их от браузера
if i <= 0 then //если ошибка/соединение закрыто, то:
begin
VirtualFree(buf, 0, MEM_RELEASE);
goto 3;
end;
send(TargetSock, buf^, i, 0); //передаем клиенту
VirtualFree(buf, 0, MEM_RELEASE); //освобождаем память
end;
if FD_IsSet(TargetSock, fset) then //если есть данные от таргета, то:
begin
avail_bytes:= 0;
ioctlsocket(TargetSock, FIONREAD, avail_bytes); //читаем кол-во пришедших байт
buf:= VirtualAlloc(nil, avail_bytes, MEM_COMMIT, PAGE_READWRITE); //освобождаем под них память
i:= recv(TargetSock, buf^, avail_bytes, 0); //принимаем их от таргета
if i <= 0 then //если ошибка/соединение закрыто, то:
begin
VirtualFree(buf, 0, MEM_RELEASE);
goto 3;
end;
send(BSock, buf^, i, 0);
VirtualFree(buf, 0, MEM_RELEASE); //освобождаем память
end;
end; //while true do
3:
CloseSocket(BSock); //закрываем сокет браузера
CloseSocket(TargetSock); //закрываем сокет таргета
Result:= 0;
ExitThread(0); //выходим из потока
end;
var sock, ClientSock: TSocket;
wdata: TWSAData;
saddr: sockaddr_in;
id: DWORD;
label 1;
begin
if WSAStartup(MAKEWORD(1, 1), wdata) <> 0 then ExitProcess(0);
sock:= socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if sock = INVALID_SOCKET then ExitProcess(0);
ZeroMemory(@saddr, sizeof(saddr));
saddr.sin_family:= PF_INET;
saddr.sin_port:= htons(8080); //будем слушать на 8080 порту
saddr.sin_addr.S_addr:= inet_addr(IpToListen); //127.0.0.1
if bind(sock, saddr, sizeof(sockaddr_in)) <> 0 then ExitProcess(0);
if listen(sock, SOMAXCONN) <> 0 then ExitProcess(0);
1:
ClientSock:= accept(sock, nil, nil);
CreateThread(nil, 0, @OurBrowserListening, pointer(ClientSock), 0, id);
goto 1; //Если подключился, ждем подключения снова.
WSACleanup();
end.
Я так думаю, что проблема зарыта где-то уже на этапе перенаправления данных от браузера к таргету и наоборот, но где именно - не могу найти никак, скоро на стену полезу. Надеюсь на вашу помощь.
Тому, кто поможет, скромное вознаграждение размером в 20$. Очень надеюсь на вас, а то я уже сломал мозг.
Проблема заключается в некорректности работы сокс-сервера через соксификаторы.
Для наглядности, чтоб было максимально понятно написал простейший socks4 сервер с подробнейшими комментариями (Delphi, WinSock + WinApi).
Качаем соксификатор (http://www.freecap.ru/?p=download), настраиваем в нем socks4 (Сервер: 127.0.0.1, порт: 8080).
Качаем исходник socks4-сервера (http://www.sendspace.com/file/ehy83w) (залил для большей наглядности)
Компилируем, запускаем, заходим на mail.ru - страница грузится очень долго (конца загрузки дождаться мне так и не удалось), хотя тот же гугл, да и вконтакт (по крайней мере на "Поиске людей") работают норм.
Так вот, нужна подсказка, из-за чего это происходит и как это исправить.
Код:
program Socks4;
uses
Windows,
WinSock;
const IpToListen = '127.0.0.1';
function OurBrowserListening(p: pointer): DWORD; stdcall;
var BSock: TSocket;
vn, cd, UserID: byte;
answer: array[1..8] of byte;
buf: pointer;
addr: sockaddr_in;
TargetSock: TSocket;
fset: tfdset;
i: integer;
avail_bytes: integer;
time_out: timeval;
label 2, 3;
begin
BSock:= Cardinal(p); //BSock - браузер (подключеный клиент)
TargetSock:= socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
//TargetSock - таргет (цель, конечный хост)
if TargetSock = INVALID_SOCKET then ExitThread(0);
ZeroMemory(@addr, sizeof(addr));
addr.sin_family:= PF_INET;
//Теперь нужно принять данные от браузера (клиента):
// +----+----+----+----+----+----+----+----+----+----+....+----+
// | VN | CD | DSTPORT | DSTIP | USERID |NULL|
// +----+----+----+----+----+----+----+----+----+----+....+----+
// 1 1 2 4 variable 1
recv(BSock, vn, sizeof(vn), 0); //принимаем версию socks - 4
recv(BSock, cd, sizeof(cd), 0); //принимаем команду - 1 (connect)
if cd <> $01 then goto 2; //если не connect, то перейти к метке 2
recv(BSock, addr.sin_port, 2, 0); //принимаем порт таргета (цели)
recv(BSock, addr.sin_addr.S_addr, 4, 0); //принимаем ip таргета (цели)
repeat
recv(BSock, UserID, sizeof(UserID), 0);
until UserID = $00; //принимаем UserID, оканчивающийся NULL-байтом
//пытаемся соединиться с таргетом
if connect(TargetSock, addr, sizeof(addr)) <> 0 then
begin //если не удалось, то:
2:ZeroMemory(@answer, sizeof(answer));
answer[1]:= $00; //должен быть 0
answer[2]:= $5B; //$5B - ошибка
send(BSock, answer, sizeof(answer), 0); //посылаем ответ браузеру (клиенту)
goto 3;
end;
//Теперь нужно послать ответ браузеру (клиенту)
// +----+----+----+----+----+----+----+----+
// | VN | CD | DSTPORT | DSTIP |
// +----+----+----+----+----+----+----+----+
// 1 1 2 4
ZeroMemory(@answer, sizeof(answer));
answer[1]:= $00; //должен быть 0
answer[2]:= $5A; //$5A - коннект к таргету успешен
send(BSock, answer, sizeof(answer), 0); //посылаем ответ браузеру (клиенту)
//Теперь следует непосредственно перенаправление данных от браузера к
//таргету и наоборот
while true do
begin //while true do
FD_ZERO(fset);
FD_SET(BSock, fset);
FD_SET(TargetSock, fset);
time_out.tv_sec:= 8; //установим таймаут на select в 8 секунд
time_out.tv_usec:= 0;
if select(0, @fset, nil, nil, @time_out) <= 0 then
goto 3;
//если есть данные от браузера и/или таргета, то:
if FD_IsSet(BSock, fset) then //если есть данные от браузера, то:
begin
avail_bytes:= 0;
ioctlsocket(BSock, FIONREAD, avail_bytes); //читаем кол-во пришедших байт
buf:= VirtualAlloc(nil, avail_bytes, MEM_COMMIT, PAGE_READWRITE); //освобождаем под них память
i:= recv(BSock, buf^, avail_bytes, 0); //принимаем их от браузера
if i <= 0 then //если ошибка/соединение закрыто, то:
begin
VirtualFree(buf, 0, MEM_RELEASE);
goto 3;
end;
send(TargetSock, buf^, i, 0); //передаем клиенту
VirtualFree(buf, 0, MEM_RELEASE); //освобождаем память
end;
if FD_IsSet(TargetSock, fset) then //если есть данные от таргета, то:
begin
avail_bytes:= 0;
ioctlsocket(TargetSock, FIONREAD, avail_bytes); //читаем кол-во пришедших байт
buf:= VirtualAlloc(nil, avail_bytes, MEM_COMMIT, PAGE_READWRITE); //освобождаем под них память
i:= recv(TargetSock, buf^, avail_bytes, 0); //принимаем их от таргета
if i <= 0 then //если ошибка/соединение закрыто, то:
begin
VirtualFree(buf, 0, MEM_RELEASE);
goto 3;
end;
send(BSock, buf^, i, 0);
VirtualFree(buf, 0, MEM_RELEASE); //освобождаем память
end;
end; //while true do
3:
CloseSocket(BSock); //закрываем сокет браузера
CloseSocket(TargetSock); //закрываем сокет таргета
Result:= 0;
ExitThread(0); //выходим из потока
end;
var sock, ClientSock: TSocket;
wdata: TWSAData;
saddr: sockaddr_in;
id: DWORD;
label 1;
begin
if WSAStartup(MAKEWORD(1, 1), wdata) <> 0 then ExitProcess(0);
sock:= socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if sock = INVALID_SOCKET then ExitProcess(0);
ZeroMemory(@saddr, sizeof(saddr));
saddr.sin_family:= PF_INET;
saddr.sin_port:= htons(8080); //будем слушать на 8080 порту
saddr.sin_addr.S_addr:= inet_addr(IpToListen); //127.0.0.1
if bind(sock, saddr, sizeof(sockaddr_in)) <> 0 then ExitProcess(0);
if listen(sock, SOMAXCONN) <> 0 then ExitProcess(0);
1:
ClientSock:= accept(sock, nil, nil);
CreateThread(nil, 0, @OurBrowserListening, pointer(ClientSock), 0, id);
goto 1; //Если подключился, ждем подключения снова.
WSACleanup();
end.
Я так думаю, что проблема зарыта где-то уже на этапе перенаправления данных от браузера к таргету и наоборот, но где именно - не могу найти никак, скоро на стену полезу. Надеюсь на вашу помощь.
Тому, кто поможет, скромное вознаграждение размером в 20$. Очень надеюсь на вас, а то я уже сломал мозг.