📄 idsocks.pas
字号:
3: Lpos := LBuf[4] + 2; // 2 is for port length
// IP V6 - 4:
else
Lpos := 16 + 2; // 16 is for address and 2 is for port length
end;
// Socks server replies on connect, this is the second part
AIOHandler.ReadBytes(LBuf, Lpos, False); // just write it over the first part for now
TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(IntToStr(LBuf[0])+'.'+IntToStr(LBuf[1])+'.'+IntToStr(LBuf[2])+'.'+IntToStr(LBuf[3]),LBuf[4]*256+LBuf[5]);
end;
end;
function TIdSocksInfo.MakeSocks4Listen(AIOHandler: TIdIOHandler;
const ATimeOut: integer): boolean;
var
LBuf: TIdBytes;
begin
SetLength(LBuf, 6);
Result := TIdIOHandlerSocket(AIOHandler).Binding.Readable(ATimeOut);
if Result then begin
AIOHandler.ReadBytes(LBuf, 2, False); // Socks server replies on connect, this is the first part
case LBuf[1] of // OpCode
90: ;// request granted, do nothing
91: raise EIdSocksRequestFailed.Create(RSSocksRequestFailed);
92: raise EIdSocksRequestServerFailed.Create(RSSocksRequestServerFailed);
93: raise EIdSocksRequestIdentFailed.Create(RSSocksRequestIdentFailed);
else raise EIdSocksUnknownError.Create(RSSocksUnknownError);
end;
// Socks server replies on connect, this is the second part
AIOHandler.ReadBytes(LBuf, 6, False); // just write it over the first part for now
TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(IntToStr(LBuf[2])+'.'+IntToStr(LBuf[3])+'.'+IntToStr(LBuf[4])+'.'+IntToStr(LBuf[5]) , LBuf[0]*256+LBuf[1]);
end;
end;
procedure TIdSocksInfo.CloseSocks5UDPAssociation;
begin
if Assigned(FUDPSocksAssociation) then
begin
FUDPSocksAssociation.Close;
end;
end;
procedure TIdSocksInfo.MakeSocks5UDPAssociation(AHandle: TIdSocketHandle);
var
Lpos: Integer;
LBuf: TIdBytes;
begin
FUDPSocksAssociation.Host := Self.Host;
FUDPSocksAssociation.Port := Self.Port;
FUDPSocksAssociation.Open;
try
SetLength(LBuf, 255);
AuthenticateSocks5Connection(FUDPSocksAssociation);
// Associate process
//For SOCKS5 Associate, the IP address and port is the client's IP address and port which may
//not be known
if AHandle.IPVersion = IdGlobal.Id_IPv4 then
begin
MakeSocks5Request(FUDPSocksAssociation, '0.0.0.0', 0, $03, LBuf, LPos); //associate request
end
else
begin
MakeSocks5Request(FUDPSocksAssociation, '::0', 0, $03, LBuf, LPos); //associate request
end;
//
FUDPSocksAssociation.Write(ToBytes(LBuf, LPos)); // send the connection packet
try
FUDPSocksAssociation.ReadBytes(LBuf, 2, False); // Socks server replies on connect, this is the first part )VER and RSP
except
raise EIdSocksServerRespondError.Create(RSSocksServerRespondError);
end;
case LBuf[1] of
0: ;// success, do nothing
1: raise EIdSocksServerGeneralError.Create(RSSocksServerGeneralError);
2: raise EIdSocksServerPermissionError.Create(RSSocksServerPermissionError);
3: raise EIdSocksServerNetUnreachableError.Create(RSSocksServerNetUnreachableError);
4: raise EIdSocksServerHostUnreachableError.Create(RSSocksServerHostUnreachableError);
5: raise EIdSocksServerConnectionRefusedError.Create(RSSocksServerConnectionRefusedError);
6: raise EIdSocksServerTTLExpiredError.Create(RSSocksServerTTLExpiredError);
7: raise EIdSocksServerCommandError.Create(RSSocksServerCommandError);
8: raise EIdSocksServerAddressError.Create(RSSocksServerAddressError);
else
raise EIdSocksUnknownError.Create(RSSocksUnknownError);
end;
FUDPSocksAssociation.ReadBytes(LBuf, 2, False); //Now get RSVD and ATYPE feilds
// type of destination address is domain name
case LBuf[1] of
// IP V4
1: Lpos := 4 + 2; // 4 is for address and 2 is for port length
// FQDN
3: Lpos := LBuf[4] + 2; // 2 is for port length
// IP V6
4: LPos := 16 + 2; // 16 is for address and 2 is for port length
end;
try
// Socks server replies on connect, this is the second part
FUDPSocksAssociation.ReadBytes(LBuf, Lpos, False); //overwrite the first part for now
AHandle.SetPeer( (FUDPSocksAssociation as TIdIOHandlerStack).Binding.PeerIP ,LBuf[4]*256+LBuf[5]); //IntToStr(LBuf[0])+'.'+IntToStr(LBuf[1])+'.'+IntToStr(LBuf[2])+'.'+IntToStr(LBuf[3])
AHandle.Connect;
except
raise EIdSocksServerRespondError.Create(RSSocksServerRespondError);
end;
except
on E: Exception do
begin
FUDPSocksAssociation.Close;
raise;
end;
end;
end;
procedure TIdSocksInfo.CloseUDP(AHandle: TIdSocketHandle);
begin
case Version of
svSocks4, svSocks4A: raise EIdSocksUDPNotSupportedBySOCKSVersion.Create(RSSocksUDPNotSupported);
svSocks5: CloseSocks5UDPAssociation;
end;
end;
procedure TIdSocksInfo.OpenUDP(AHandle: TIdSocketHandle;
const AHost: string=''; const APort: Integer=0);
begin
case Version of
svSocks4, svSocks4A: raise EIdSocksUDPNotSupportedBySOCKSVersion.Create(RSSocksUDPNotSupported);
svSocks5: MakeSocks5UDPAssociation(AHandle);
end;
end;
function TIdSocksInfo.DisasmUDPReplyPacket(const APacket : TIdBytes;
var VHost : String; var VPort : Integer): TIdBytes;
{
+----+------+------+----------+----------+----------+
|RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
+----+------+------+----------+----------+----------+
| 2 | 1 | 1 | Variable | 2 | Variable |
+----+------+------+----------+----------+----------+
01 2 3
The fields in the UDP request header are:
o RSV Reserved X'0000'
o FRAG Current fragment number
o ATYP address type of following addresses:
o IP V4 address: X'01'
o DOMAINNAME: X'03'
o IP V6 address: X'04'
o DST.ADDR desired destination address
o DST.PORT desired destination port
o DATA user data
}
var LLen : Integer;
// LIP : TIdIPAddress;
LIP6 : TIdIPv6Address;
LtempPort : Word;
LHost : TIdBytes;
i : Integer;
begin
if Length(APacket)<5 then
begin
Exit;
end;
// type of destination address is domain name
case APacket[3] of
// IP V4
1: begin
LLen := 4 + 4; //4 IPv4 address len, 4- 2 reserved, 1 frag, 1 atype
VHost := IntToStr(APacket[4])+'.'+IntToStr(APacket[5])+'.'+IntToStr(APacket[6])+'.'+IntToStr(APacket[7]);
end;
// FQDN
3: begin
LLen := APacket[4] +4; // 2 is for port length, 4 - 2 reserved, 1 frag, 1 atype
if Length(APacket)< (5+LLen) then
begin
Exit;
end;
SetLength(LHost,APacket[4]);
CopyTIdBytes(APacket,5,LHost,0,APacket[4]);
VHost := BytesToString(LHost);
end;
// IP V6 - 4:
else
LLen := 16 + 4; // 16 is for address, 2 is for port length,4 - 2 reserved, 1 frag, 1 atype
SetLength(LHost,16);
CopyTIdBytes(APacket,5,LHost,0,16);
LIP6 := BytesToIPv6(LHost);
for i := 0 to 7 do
begin
LIP6[i] := GStack.NetworkToHost(LIP6[i]);
end;
VHost := IPv6AddressToStr(LIP6);
end;
LtempPort := APacket[LLen]*256+ APacket[LLen+1];
VPort := LtempPort;
LLen := LLen + 2;
SetLength(Result,Length(APacket)-LLen);
CopyTIdBytes(APacket,LLen,Result,0,Length(APacket)-LLen);
end;
function TIdSocksInfo.MakeUDPRequestPacket(const AData: TIdBytes;
const AHost : String; const APort : Integer) : TIdBytes;
{
+----+------+------+----------+----------+----------+
|RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
+----+------+------+----------+----------+----------+
| 2 | 1 | 1 | Variable | 2 | Variable |
+----+------+------+----------+----------+----------+
01 2 3
The fields in the UDP request header are:
o RSV Reserved X'0000'
o FRAG Current fragment number
o ATYP address type of following addresses:
o IP V4 address: X'01'
o DOMAINNAME: X'03'
o IP V6 address: X'04'
o DST.ADDR desired destination address
o DST.PORT desired destination port
o DATA user data
}
var LLen : Integer;
LIP : TIdIPAddress;
LtempPort : Word;
begin
SetLength(Result,1024);
Result[0] := 0;
Result[1] := 0;
Result[2] := 0; //no fragmentation - too lazy to implement it
if (length(MakeCanonicalIPv6Address(AHost))>0) then begin
Result[3] := $4; // address type: IP V4 address: X'01' {Do not Localize}
// DOMAINNAME: X'03' {Do not Localize}
// IP V6 address: X'04' {Do not Localize}
Result[4] :=16; // 16 bytes for the ip
LLen := 5;
LIP := TIdIPAddress.MakeAddressObject(AHost);
try
if Assigned(LIP) then
begin
CopyTIdBytes(LIP.HToNBytes,0,Result,4,16);
end;
finally
FreeAndNil(LIP);
end;
LLen := LLen + 16;
end
else
begin
// for now we stick with domain name, must ask Chad how to detect
// address type
if GStack.IsIP( AHost ) then
begin
Result[3] := $01; //IPv4 address
Result[4] :=4; // 4 bytes for the ip
LIP := TIdIPAddress.MakeAddressObject(AHost);
try
if Assigned(LIP) then
begin
CopyTIdBytes(LIP.HToNBytes,0,Result,4,4);
end;
finally
FreeAndNil(LIP);
end;
LLen := 8;
end
else
begin
Result[3] := $3; // address type: IP V4 address: X'01' {Do not Localize}
// DOMAINNAME: X'03' {Do not Localize}
// IP V6 address: X'04' {Do not Localize}
// host name
Result[4] := Length(AHost);
LLen := 5;
if Length(AHost) > 0 then begin
CopyTIdBytes(ToBytes(AHost),0,Result,LLen,Length(AHost));
end;
LLen := LLen + Length(AHost);
end;
end;
// port
LtempPort := APort; //done this way to avoid a range check error
LtempPort := GStack.HostToNetwork(LtempPort);
CopyTIdBytes(ToBytes(LtempPort),0,Result,LLen,2);
LLen := LLen + 2;
//now do the rest of the packet
SetLength(Result,LLen + Length(AData));
CopyTIdBytes(AData,0,Result,LLen,Length(AData));
end;
function TIdSocksInfo.RecvFromUDP(AHandle: TIdSocketHandle;
var ABuffer : TIdBytes;
var VPeerIP: string; var VPeerPort: integer;
AMSec: Integer = IdTimeoutDefault): integer;
var LBuf : TIdBytes;
begin
case Version of
svSocks4, svSocks4A: raise EIdSocksUDPNotSupportedBySOCKSVersion.Create(RSSocksUDPNotSupported);
end;
SetLength(LBuf,Length(ABuffer)+200);
if not AHandle.Readable(AMSec) then begin
Result := 0;
VPeerIP := ''; {Do not Localize}
VPeerPort := 0;
Exit;
end;
Result := AHandle.RecvFrom(LBuf,VPeerIP, VPeerPort);
SetLength(LBuf,Result);
LBuf := DisasmUDPReplyPacket(LBuf, VPeerIP, VPeerPort);
Result := Length(LBuf);
IdGlobal.CopyTIdBytes(LBuf,0,ABuffer,0,Result);
end;
procedure TIdSocksInfo.SendToUDP(AHandle: TIdSocketHandle;
AHost: string; const APort: Integer; const ABuffer : TIdBytes);
var LBuf : TIdBytes;
begin
case Version of
svSocks4, svSocks4A: raise EIdSocksUDPNotSupportedBySOCKSVersion.Create(RSSocksUDPNotSupported);
end;
LBuf := MakeUDPRequestPacket(ABuffer, AHost,APort);
AHandle.Send(LBuf,0);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -