/ProSnooperFx_src/indy10.0.52_source/Core/IdSocks.pas
Pascal | 1009 lines | 668 code | 72 blank | 269 comment | 33 complexity | 200813fce1a85431497b48928ab5516e MD5 | raw file
- { $HDR$}
- {**********************************************************************}
- { Unit archived using Team Coherence }
- { Team Coherence is Copyright 2002 by Quality Software Components }
- { }
- { For further information / comments, visit our WEB site at }
- { http://www.TeamCoherence.com }
- {**********************************************************************}
- {}
- { $Log: 11984: IdSocks.pas
- {
- { Rev 1.36 11/11/2004 10:25:24 PM JPMugaas
- { Added OpenProxy and CloseProxy so you can do RecvFrom and SendTo functions
- { from the UDP client with SOCKS. You must call OpenProxy before using
- { RecvFrom or SendTo. When you are finished, you must use CloseProxy to close
- { any connection to the Proxy. Connect and disconnect also call OpenProxy and
- { CloseProxy.
- }
- {
- { Rev 1.35 11/11/2004 3:42:50 AM JPMugaas
- { Moved strings into RS. Socks will now raise an exception if you attempt to
- { use SOCKS4 and SOCKS4A with UDP. Those protocol versions do not support UDP
- { at all.
- }
- {
- { Rev 1.34 11/10/2004 10:55:58 PM JPMugaas
- { UDP Association bug fix - we now send 0's for IP address and port.
- }
- {
- { Rev 1.33 11/10/2004 10:38:42 PM JPMugaas
- { Bug fixes - UDP with SOCKS now works.
- }
- {
- { Rev 1.32 11/10/2004 9:42:54 PM JPMugaas
- { 1 in a reserved position should be 0 in a UDP request packet.
- }
- {
- { Rev 1.31 11/9/2004 8:18:00 PM JPMugaas
- { Attempt to add SOCKS support in UDP.
- }
- {
- { Rev 1.30 03/07/2004 10:08:22 CCostelloe
- { Removed spurious code that generates warning
- }
- {
- { Rev 1.29 6/9/04 7:44:44 PM RLebeau
- { various ReadBytes() tweaks
- {
- { updated MakeSocks4Request() to call AIOHandler.WriteBufferCancel() on error.
- }
- {
- { Rev 1.28 2004.05.20 1:39:58 PM czhower
- { Last of the IdStream updates
- }
- {
- { Rev 1.27 2004.05.20 9:19:24 AM czhower
- { Removed unused var
- }
- {
- Rev 1.26 5/19/2004 10:44:42 PM DSiders
- Corrected spelling for TIdIPAddress.MakeAddressObject method.
- }
- {
- { Rev 1.25 5/19/2004 2:44:40 PM JPMugaas
- { Fixed compiler warnings in TIdSocksInfo.Listen.
- }
- {
- { Rev 1.24 5/8/2004 3:45:34 PM BGooijen
- { Listen works in Socks 4 now
- }
- {
- { Rev 1.23 5/7/2004 4:52:44 PM JPMugaas
- { Bind in SOCKS4 should work a bit better. There's still some other work that
- { needs to be done on it.
- }
- {
- { Rev 1.22 5/7/2004 8:54:54 AM JPMugaas
- { Attempt to add SOCKS4 bind.
- }
- {
- { Rev 1.21 5/7/2004 7:43:24 AM JPMugaas
- { Checked Bas's changes.
- }
- {
- { Rev 1.20 5/7/2004 5:53:20 AM JPMugaas
- { Removed some duplicate code to reduce the probability of error.
- }
- {
- { Rev 1.19 5/7/2004 1:44:12 AM BGooijen
- { Bind
- }
- {
- { Rev 1.18 5/6/2004 6:47:04 PM JPMugaas
- { Attempt to work on bind further.
- }
- {
- { Rev 1.16 5/6/2004 5:32:58 PM JPMugaas
- { Port was being mangled because the compiler was assuming you wanted a 4 byte
- { byte order instead of only a two byte byte order function.
- { IP addresses are better handled. At least I can connect again.
- }
- {
- { Rev 1.15 5/5/2004 2:09:40 PM JPMugaas
- { Attempt to reintroduce bind and listen functionality for FTP.
- }
- {
- { Rev 1.14 2004.03.07 11:48:44 AM czhower
- { Flushbuffer fix + other minor ones found
- }
- {
- { Rev 1.13 2004.02.03 4:16:52 PM czhower
- { For unit name changes.
- }
- {
- { Rev 1.12 2/2/2004 2:33:04 PM JPMugaas
- { Should compile better.
- }
- {
- { Rev 1.11 2/2/2004 12:23:16 PM JPMugaas
- { Attempt to fix the last Todo concerning IPv6.
- }
- {
- { Rev 1.10 2/2/2004 11:43:08 AM BGooijen
- { DotNet
- }
- {
- { Rev 1.9 2/2/2004 12:00:08 AM BGooijen
- { Socks 4 / 4A working again
- }
- {
- { Rev 1.8 2004.01.20 10:03:34 PM czhower
- { InitComponent
- }
- {
- { Rev 1.7 1/11/2004 10:45:56 PM BGooijen
- { Socks 5 works on D7 now, Socks 4 almost
- }
- {
- { Rev 1.6 2003.10.11 5:50:34 PM czhower
- { -VCL fixes for servers
- { -Chain suport for servers (Super core)
- { -Scheduler upgrades
- { -Full yarn support
- }
- {
- { Rev 1.5 2003.10.01 1:37:34 AM czhower
- { .Net
- }
- {
- { Rev 1.4 2003.09.30 7:37:28 PM czhower
- { Updates for .net
- }
- {
- Rev 1.3 4/2/2003 3:23:00 PM BGooijen
- fixed and re-enabled
- }
- {
- { Rev 1.2 2003.01.10 8:21:04 PM czhower
- { Removed more warnings
- }
- {
- { Rev 1.1 2003.01.10 7:21:14 PM czhower
- { Removed warnings
- }
- {
- { Rev 1.0 11/13/2002 08:58:56 AM JPMugaas
- }
- unit IdSocks;
- interface
- uses
- Classes, IdAssignedNumbers, IdException,
- IdComponent, IdCustomTransparentProxy, IdGlobal, IdIOHandler, IdSocketHandle;
- type
- EIdSocksUDPNotSupportedBySOCKSVersion = class(EIdException);
- TSocksVersion = (svNoSocks, svSocks4, svSocks4A, svSocks5);
- TSocksAuthentication = (saNoAuthentication, saUsernamePassword);
- const
- ID_SOCKS_AUTH = saNoAuthentication;
- ID_SOCKS_VER = svNoSocks;
- type
- TIdSocksInfo = class(TIdCustomTransparentProxy)
- protected
- FAuthentication: TSocksAuthentication;
- FVersion: TSocksVersion;
- FUDPSocksAssociation : TIdIOHandler;
- //
- function DisasmUDPReplyPacket(const APacket : TIdBytes;
- var VHost : String; var VPort : Integer): TIdBytes;
- function MakeUDPRequestPacket(const AData: TIdBytes;
- const AHost : String; const APort : Integer) : TIdBytes;
- procedure AssignTo(ASource: TPersistent); override;
- function GetEnabled: Boolean; override;
- procedure InitComponent; override;
- procedure AuthenticateSocks5Connection(AIOHandler: TIdIOHandler);
- // This must be defined with an port value that's a word so that we use the 2 byte Network Order byte functions instead
- // the 4 byte or 8 byte functions. If we use the wrong byte order functions, we can get a zero port value causing an error.
- procedure MakeSocks4Request(AIOHandler: TIdIOHandler; const AHost: string; const APort: Word; const ARequest : Byte);
- procedure MakeSocks5Request(AIOHandler: TIdIOHandler; const AHost: string; const APort: Word; const ARequest : Byte; var VBuf : TIdBytes; var VLen : Integer);
- procedure MakeSocks4Connection(AIOHandler: TIdIOHandler; const AHost: string; const APort: Integer);
- procedure MakeSocks4Bind(AIOHandler: TIdIOHandler; const AHost: string; const APort: Integer);
- procedure MakeSocks5Connection(AIOHandler: TIdIOHandler; const AHost: string; const APort: Integer);
- procedure MakeSocks5Bind(AIOHandler: TIdIOHandler; const AHost: string;
- const APort: Integer);
- procedure MakeConnection(AIOHandler: TIdIOHandler; const AHost: string; const APort: Integer); override;
- function MakeSocks4Listen(AIOHandler: TIdIOHandler; const ATimeOut:integer):boolean;
- function MakeSocks5Listen(AIOHandler: TIdIOHandler; const ATimeOut:integer):boolean;
- //association for UDP
- procedure MakeSocks5UDPAssociation(AHandle : TIdSocketHandle);
- procedure CloseSocks5UDPAssociation;
- public
- procedure Bind(AIOHandler: TIdIOHandler; const AHost: string; const APort: Integer); override;
- function Listen(AIOHandler: TIdIOHandler; const ATimeOut:integer):boolean;override;
- procedure OpenUDP(AHandle : TIdSocketHandle; const AHost: string=''; const APort: Integer=0); override;
- function RecvFromUDP(AHandle: TIdSocketHandle;
- var ABuffer : TIdBytes;
- var VPeerIP: string; var VPeerPort: integer;
- AMSec: Integer = IdTimeoutDefault): integer; override;
- procedure SendToUDP(AHandle: TIdSocketHandle;
- AHost: string; const APort: Integer; const ABuffer : TIdBytes); override;
- procedure CloseUDP(AHandle: TIdSocketHandle); override;
- published
- property Authentication: TSocksAuthentication read FAuthentication write FAuthentication default ID_SOCKS_AUTH;
- property Host;
- property Password;
- property Port default IdPORT_SOCKS;
- property Username;
- property Version: TSocksVersion read FVersion write FVersion default ID_SOCKS_VER;
- property ChainedProxy;
- End;//TIdSocksInfo
- implementation
- uses
- IdIOHandlerSocket,
- IdResourceStringsCore, IdExceptionCore, IdIPAddress, IdStack,
- IdTCPClient,
- IdIOHandlerStack,
- SysUtils;
- { TIdSocksInfo }
- procedure TIdSocksInfo.AssignTo(ASource: TPersistent);
- begin
- if ASource is TIdSocksInfo then begin
- inherited AssignTo(ASource);
- with TIdSocksInfo(ASource) do begin
- Authentication := Self.Authentication;
- Version := Self.Version;
- end;
- end else begin
- inherited AssignTo(ASource);
- end;
- end;
- procedure TIdSocksInfo.MakeSocks4Request(AIOHandler: TIdIOHandler; const AHost: string; const APort: Word; const ARequest : Byte);
- var
- LIpAddr: String;
- LTempPort : Word;
- begin
- AIOHandler.WriteBufferOpen;
- try
- AIOHandler.Write(ToBytes(Byte(4))); // Version
- AIOHandler.Write(ToBytes(ARequest)); // Opcode
- LTempPort := GStack.HostToNetwork(APort);
- AIOHandler.Write(ToBytes(LTempPort)); // Port
- if Version = svSocks4A then begin
- LIpAddr := '0.0.0.1'; {Do not Localize}
- end else begin
- LIpAddr := GStack.ResolveHost(AHost,Id_IPv4);
- end;
- AIOHandler.Write(ToBytes(Byte(StrToInt(Fetch(LIpAddr,'.')))));// IP
- AIOHandler.Write(ToBytes(Byte(StrToInt(Fetch(LIpAddr,'.')))));// IP
- AIOHandler.Write(ToBytes(Byte(StrToInt(Fetch(LIpAddr,'.')))));// IP
- AIOHandler.Write(ToBytes(Byte(StrToInt(Fetch(LIpAddr,'.')))));// IP
- AIOHandler.Write(ToBytes(Username));
- AIOHandler.Write(ToBytes(Byte(0)));// Username
- if Version = svSocks4A then begin
- AIOHandler.Write(ToBytes(AHost));
- AIOHandler.Write(ToBytes(Byte(0)));// Host
- end;
- AIOHandler.WriteBufferClose; //flush everything
- except
- AIOHandler.WriteBufferCancel; //cancel everything
- raise;
- end;
- end;
- procedure TIdSocksInfo.MakeSocks4Connection(AIOHandler: TIdIOHandler; const AHost: string; const APort: Integer);
- var
- LResponse: TIdBytes;
- begin
- MakeSocks4Request(AIOHandler, AHost, APort,$01); //connect
- AIOHandler.ReadBytes(LResponse, 8, False);
- case LResponse[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;
- end;
- procedure TIdSocksInfo.MakeSocks5Request(AIOHandler: TIdIOHandler; const AHost: string; const APort: Word; const ARequest : Byte; var VBuf : TIdBytes; var VLen : Integer);
- var LtempPort : Word;
- LIP : TIdIPAddress;
- begin
- // Connection process
- VBuf[0] := $5; // socks version
- VBuf[1] := ARequest; //request method
- VBuf[2] := $0; // reserved
- if (length(MakeCanonicalIPv6Address(AHost))>0) then begin
- VBuf[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}
- VBuf[4] :=16; // 16 bytes for the ip
- VLen := 5;
- LIP := TIdIPAddress.MakeAddressObject(AHost);
- try
- if Assigned(LIP) then
- begin
- CopyTIdBytes(LIP.HToNBytes,0,VBuf,4,16);
- end;
- finally
- FreeAndNil(LIP);
- end;
- VLen := VLen + 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
- VBuf[3] := $01; //IPv4 address
- LIP := TIdIPAddress.MakeAddressObject(AHost);
- try
- if Assigned(LIP) then
- begin
- CopyTIdBytes(LIP.HToNBytes,0,VBuf,4,4);
- end;
- finally
- FreeAndNil(LIP);
- end;
- VLen := 8;
- end
- else
- begin
- VBuf[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
- VBuf[4] := Length(AHost);
- VLen := 5;
- if Length(AHost) > 0 then begin
- CopyTIdBytes(ToBytes(AHost),0,VBuf,VLen,Length(AHost));
- end;
- VLen := VLen + Length(AHost);
- end;
- end;
- // port
- LtempPort := GStack.HostToNetwork(APort);
- CopyTIdBytes(ToBytes(LtempPort),0,VBuf,VLen,2);
- VLen := VLen + 2;
- end;
- procedure TIdSocksInfo.MakeSocks5Connection(AIOHandler: TIdIOHandler; const AHost: string; const APort: Integer);
- var
- pos: Integer;
- LBuf: TIdBytes;
- begin
- AuthenticateSocks5Connection(AIOHandler);
- SetLength(LBuf, 255);
- MakeSocks5Request(AIOHandler, AHost, APort, $01, LBuf, Pos);
- AIOHandler.WriteDirect(ToBytes(LBuf, pos)); // send the connection packet
- try
- AIOHandler.ReadBytes(LBuf, 5, False); // Socks server replies on connect, this is the first part
- 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;
- // type of destination address is domain name
- case LBuf[3] of
- // IP V4
- 1: pos := 4 + 2; // 4 is for address and 2 is for port length
- // FQDN
- 3: pos := LBuf[4] + 2; // 2 is for port length
- // IP V6
- 4: pos := 16 + 2; // 16 is for address and 2 is for port length
- end;
- try
- // Socks server replies on connect, this is the second part
- // RLebeau: why -1?
- AIOHandler.ReadBytes(LBuf, pos-1, False); // just write it over the first part for now
- except
- raise EIdSocksServerRespondError.Create(RSSocksServerRespondError);
- end;
- end;
- procedure TIdSocksInfo.MakeSocks4Bind(AIOHandler: TIdIOHandler; const AHost: string; const APort: Integer);
- var
- LResponse: TIdBytes;
- LClient: TIdTcpClient;
- begin
- LClient := TIdTCPClient.Create(nil);
- try
- // SetLength(LResponse, 255);
- SetLength(LResponse, 8);
- TIdIOHandlerSocket(AIOHandler).TransparentProxy := nil;
- LClient.IOHandler := AIOHandler;
- LClient.Host := Host;
- LClient.Port := Port;
- LClient.Connect;
- TIdIOHandlerSocket(AIOHandler).TransparentProxy := Self;
- MakeSocks4Request(AIOHandler, AHost, APort, $02); //bind
- AIOHandler.ReadBytes(LResponse, 2, False);
- case LResponse[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;
- try
- // Socks server replies on connect, this is the second part
- AIOHandler.ReadBytes(LResponse, 6, False); //overwrite the first part for now
- TIdIOHandlerSocket(AIOHandler).Binding.SetBinding( IntToStr(LResponse[2])+'.'+IntToStr(LResponse[3])+'.'+IntToStr(LResponse[4])+'.'+IntToStr(LResponse[5]) , LResponse[0]*256+LResponse[1]);
- except
- raise EIdSocksServerRespondError.Create(RSSocksServerRespondError);
- end;
- finally
- LClient.IOHandler := nil;
- FreeAndNil(LClient);
- end;
- end;
- procedure TIdSocksInfo.MakeConnection(AIOHandler: TIdIOHandler; const AHost: string; const APort: Integer);
- begin
- case Version of
- svSocks4, svSocks4A: MakeSocks4Connection(AIOHandler, AHost, APort);
- svSocks5: MakeSocks5Connection(AIOHandler, AHost, APort);
- end;
- end;
- function TIdSocksInfo.GetEnabled: Boolean;
- Begin
- Result := Version in [svSocks4, svSocks4A, svSocks5];
- End;//
- procedure TIdSocksInfo.InitComponent;
- begin
- inherited;
- Authentication := ID_SOCKS_AUTH;
- Version := ID_SOCKS_VER;
- Port := IdPORT_SOCKS;
- FUDPSocksAssociation := TIdIOHandlerStack.Create;
- end;
- procedure TIdSocksInfo.AuthenticateSocks5Connection(
- AIOHandler: TIdIOHandler);
- var
- pos: Integer;
- LBuf: TIdBytes;
- LRequestedAuthMethod,
- LServerAuthMethod,
- LUsernameLen,
- LPasswordLen : Byte;
- begin
- SetLength(LBuf, 3);
- // defined in rfc 1928
- if Authentication = saNoAuthentication then begin
- LBuf[2] := $0 // No authentication
- end else begin
- LBuf[2] := $2; // Username password authentication
- end;
- LRequestedAuthMethod := LBuf[2];
- LBuf[0] := $5; // socks version
- LBuf[1] := $1; // number of possible authentication methods
- AIOHandler.WriteDirect(LBuf);
- try
- AIOHandler.ReadBytes(LBuf, 2, False); // Socks server sends the selected authentication method
- except
- On E: Exception do begin
- raise EIdSocksServerRespondError.Create(RSSocksServerRespondError);
- end;
- end;
- LServerAuthMethod := LBuf[1];
- if (LServerAuthMethod <> LRequestedAuthMethod) or (LServerAuthMethod = $FF) then begin
- raise EIdSocksAuthMethodError.Create(RSSocksAuthMethodError);
- end;
- // Authentication process
- if Authentication = saUsernamePassword then begin
- LUsernameLen := Length(Username);
- LPasswordLen := Length(Password);
- SetLength(LBuf, 3 + LUsernameLen + LPasswordLen);
- LBuf[0] := 1; // version of subnegotiation
- LBuf[1] := LUsernameLen;
- pos := 2;
- if LUsernameLen > 0 then begin
- CopyTIdBytes(ToBytes(Username), 0, LBuf, pos, LUsernameLen);
- pos := pos + LUsernameLen;
- end;
- LBuf[pos] := LPasswordLen;
- pos := pos + 1;
- if LPasswordLen > 0 then begin
- CopyTIdBytes(ToBytes(Password), 0, LBuf, pos, LPasswordLen);
- end;
- AIOHandler.WriteDirect(LBuf); // send the username and password
- try
- AIOHandler.ReadBytes(LBuf, 2, False); // Socks server sends the authentication status
- except
- On E: Exception do begin
- raise EIdSocksServerRespondError.Create(RSSocksServerRespondError);
- end;
- end;
- if LBuf[1] <> $0 then begin
- raise EIdSocksAuthError.Create(RSSocksAuthError);
- end;
- end;
- end;
- procedure TIdSocksInfo.MakeSocks5Bind(AIOHandler: TIdIOHandler; const AHost: string;
- const APort: Integer);
- var
- Lpos: Integer;
- LBuf: TIdBytes;
- LClient:TIdTcpClient;
- begin
- LClient := TIdTCPClient.Create(nil);
- try
- SetLength(LBuf, 255);
- TIdIOHandlerSocket(AIOHandler).TransparentProxy := nil;
- LClient.IOHandler := AIOHandler;
- LClient.Host := Host;
- LClient.Port := Port;
- LClient.Connect;
- TIdIOHandlerSocket(AIOHandler).TransparentProxy := Self;
- AuthenticateSocks5Connection(AIOHandler);
- // Bind process
- MakeSocks5Request(AIOHandler, AHost, APort, $02, LBuf, LPos); //bind request
- //
- AIOHandler.Write(ToBytes(LBuf, LPos)); // send the connection packet
- try
- AIOHandler.ReadBytes(LBuf, 4, False); // Socks server replies on connect, this is the first part
- 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;
- // type of destination address is domain name
- case LBuf[3] 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
- AIOHandler.ReadBytes(LBuf, Lpos, False); //overwrite the first part for now
- TIdIOHandlerSocket(AIOHandler).binding.SetBinding( IntToStr(LBuf[0])+'.'+IntToStr(LBuf[1])+'.'+IntToStr(LBuf[2])+'.'+IntToStr(LBuf[3]) ,LBuf[4]*256+LBuf[5]);
- except
- raise EIdSocksServerRespondError.Create(RSSocksServerRespondError);
- end;
- finally
- LClient.IOHandler := nil;
- FreeAndNil(LClient);
- end;
- end;
- procedure TIdSocksInfo.Bind(AIOHandler: TIdIOHandler; const AHost: string;
- const APort: Integer);
- begin
- case Version of
- svSocks4, svSocks4A: MakeSocks4Bind(AIOHandler, AHost, APort);
- svSocks5: MakeSocks5Bind(AIOHandler, AHost, APort);
- end;
- end;
- function TIdSocksInfo.Listen(AIOHandler: TIdIOHandler;
- const ATimeOut: integer): boolean;
- begin
- Result := False;
- case Version of
- svSocks4, svSocks4A: Result := MakeSocks4Listen(AIOHandler, ATimeOut);
- svSocks5: Result := MakeSocks5Listen(AIOHandler, ATimeOut);
- end;
- end;
- function TIdSocksInfo.MakeSocks5Listen(AIOHandler: TIdIOHandler;
- const ATimeOut: integer): boolean;
- var
- Lpos: Integer;
- LBuf: TIdBytes;
- begin
- SetLength(LBuf, 255);
- Result := TIdIOHandlerSocket(AIOHandler).Binding.Readable(ATimeOut);
- if Result then begin
- AIOHandler.ReadBytes(LBuf, 4, False); // Socks server replies on connect, this is the first part
- 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;
- // type of destination address is domain name
- case LBuf[3] 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:
- 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.