IdSocks.pas 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. $Log$
  13. Rev 1.38 11/15/2004 11:59:12 PM JPMugaas
  14. Hopefully, this should handle IPv6 addresses in SOCKS bind and listen.
  15. Rev 1.37 11/12/2004 11:30:18 AM JPMugaas
  16. Expansions for IPv6.
  17. Rev 1.36 11/11/2004 10:25:24 PM JPMugaas
  18. Added OpenProxy and CloseProxy so you can do RecvFrom and SendTo functions
  19. from the UDP client with SOCKS. You must call OpenProxy before using
  20. RecvFrom or SendTo. When you are finished, you must use CloseProxy to close
  21. any connection to the Proxy. Connect and disconnect also call OpenProxy and
  22. CloseProxy.
  23. Rev 1.35 11/11/2004 3:42:50 AM JPMugaas
  24. Moved strings into RS. Socks will now raise an exception if you attempt to
  25. use SOCKS4 and SOCKS4A with UDP. Those protocol versions do not support UDP
  26. at all.
  27. Rev 1.34 11/10/2004 10:55:58 PM JPMugaas
  28. UDP Association bug fix - we now send 0's for IP address and port.
  29. Rev 1.33 11/10/2004 10:38:42 PM JPMugaas
  30. Bug fixes - UDP with SOCKS now works.
  31. Rev 1.32 11/10/2004 9:42:54 PM JPMugaas
  32. 1 in a reserved position should be 0 in a UDP request packet.
  33. Rev 1.31 11/9/2004 8:18:00 PM JPMugaas
  34. Attempt to add SOCKS support in UDP.
  35. Rev 1.30 03/07/2004 10:08:22 CCostelloe
  36. Removed spurious code that generates warning
  37. Rev 1.29 6/9/04 7:44:44 PM RLebeau
  38. various ReadBytes() tweaks
  39. updated MakeSocks4Request() to call AIOHandler.WriteBufferCancel() on error.
  40. Rev 1.28 2004.05.20 1:39:58 PM czhower
  41. Last of the IdStream updates
  42. Rev 1.27 2004.05.20 9:19:24 AM czhower
  43. Removed unused var
  44. Rev 1.26 5/19/2004 10:44:42 PM DSiders
  45. Corrected spelling for TIdIPAddress.MakeAddressObject method.
  46. Rev 1.25 5/19/2004 2:44:40 PM JPMugaas
  47. Fixed compiler warnings in TIdSocksInfo.Listen.
  48. Rev 1.24 5/8/2004 3:45:34 PM BGooijen
  49. Listen works in Socks 4 now
  50. Rev 1.23 5/7/2004 4:52:44 PM JPMugaas
  51. Bind in SOCKS4 should work a bit better. There's still some other work that
  52. needs to be done on it.
  53. Rev 1.22 5/7/2004 8:54:54 AM JPMugaas
  54. Attempt to add SOCKS4 bind.
  55. Rev 1.21 5/7/2004 7:43:24 AM JPMugaas
  56. Checked Bas's changes.
  57. Rev 1.20 5/7/2004 5:53:20 AM JPMugaas
  58. Removed some duplicate code to reduce the probability of error.
  59. Rev 1.19 5/7/2004 1:44:12 AM BGooijen
  60. Bind
  61. Rev 1.18 5/6/2004 6:47:04 PM JPMugaas
  62. Attempt to work on bind further.
  63. Rev 1.16 5/6/2004 5:32:58 PM JPMugaas
  64. Port was being mangled because the compiler was assuming you wanted a 4 byte
  65. byte order instead of only a two byte byte order function.
  66. IP addresses are better handled. At least I can connect again.
  67. Rev 1.15 5/5/2004 2:09:40 PM JPMugaas
  68. Attempt to reintroduce bind and listen functionality for FTP.
  69. Rev 1.14 2004.03.07 11:48:44 AM czhower
  70. Flushbuffer fix + other minor ones found
  71. Rev 1.13 2004.02.03 4:16:52 PM czhower
  72. For unit name changes.
  73. Rev 1.12 2/2/2004 2:33:04 PM JPMugaas
  74. Should compile better.
  75. Rev 1.11 2/2/2004 12:23:16 PM JPMugaas
  76. Attempt to fix the last Todo concerning IPv6.
  77. Rev 1.10 2/2/2004 11:43:08 AM BGooijen
  78. DotNet
  79. Rev 1.9 2/2/2004 12:00:08 AM BGooijen
  80. Socks 4 / 4A working again
  81. Rev 1.8 2004.01.20 10:03:34 PM czhower
  82. InitComponent
  83. Rev 1.7 1/11/2004 10:45:56 PM BGooijen
  84. Socks 5 works on D7 now, Socks 4 almost
  85. Rev 1.6 2003.10.11 5:50:34 PM czhower
  86. -VCL fixes for servers
  87. -Chain suport for servers (Super core)
  88. -Scheduler upgrades
  89. -Full yarn support
  90. Rev 1.5 2003.10.01 1:37:34 AM czhower
  91. .Net
  92. Rev 1.4 2003.09.30 7:37:28 PM czhower
  93. Updates for .net
  94. Rev 1.3 4/2/2003 3:23:00 PM BGooijen
  95. fixed and re-enabled
  96. Rev 1.2 2003.01.10 8:21:04 PM czhower
  97. Removed more warnings
  98. Rev 1.1 2003.01.10 7:21:14 PM czhower
  99. Removed warnings
  100. Rev 1.0 11/13/2002 08:58:56 AM JPMugaas
  101. }
  102. unit IdSocks;
  103. interface
  104. {$I IdCompilerDefines.inc}
  105. //we need to put this in Delphi mode to work.
  106. uses
  107. Classes,
  108. IdAssignedNumbers, IdException, IdBaseComponent,
  109. IdComponent, IdCustomTransparentProxy, IdGlobal, IdIOHandler,
  110. IdIOHandlerSocket, IdSocketHandle;
  111. type
  112. EIdSocksUDPNotSupportedBySOCKSVersion = class(EIdException);
  113. TSocksVersion = (svNoSocks, svSocks4, svSocks4A, svSocks5);
  114. TSocksAuthentication = (saNoAuthentication, saUsernamePassword);
  115. const
  116. ID_SOCKS_AUTH = saNoAuthentication;
  117. ID_SOCKS_VER = svNoSocks;
  118. type
  119. TIdSocksInfo = class(TIdCustomTransparentProxy)
  120. protected
  121. FAuthentication: TSocksAuthentication;
  122. FVersion: TSocksVersion;
  123. FUDPSocksAssociation : TIdIOHandlerSocket;
  124. //
  125. function DisasmUDPReplyPacket(const APacket : TIdBytes;
  126. var VHost : String; var VPort : TIdPort; var VIPVersion: TIdIPVersion): TIdBytes;
  127. function MakeUDPRequestPacket(const AData: TIdBytes;
  128. const AHost: String; const APort: TIdPort) : TIdBytes;
  129. function GetEnabled: Boolean; override;
  130. procedure InitComponent; override;
  131. procedure AuthenticateSocks5Connection(AIOHandler: TIdIOHandler);
  132. // This must be defined with an port value that's a word so that we use the 2 byte Network Order byte functions instead
  133. // 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.
  134. procedure MakeSocks4Request(AIOHandler: TIdIOHandler; const AHost: string; const APort: TIdPort; const ARequest : Byte);
  135. procedure MakeSocks5Request(AIOHandler: TIdIOHandler; const AHost: string; const APort: TIdPort; const ARequest : Byte; var VBuf : TIdBytes; var VLen : Integer);
  136. procedure MakeSocks4Connection(AIOHandler: TIdIOHandler; const AHost: string; const APort: TIdPort);
  137. procedure MakeSocks4Bind(AIOHandler: TIdIOHandler; const AHost: string; const APort: TIdPort);
  138. procedure MakeSocks5Connection(AIOHandler: TIdIOHandler; const AHost: string; const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  139. procedure MakeSocks5Bind(AIOHandler: TIdIOHandler; const AHost: string;
  140. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  141. procedure MakeConnection(AIOHandler: TIdIOHandler; const AHost: string; const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  142. function MakeSocks4Listen(AIOHandler: TIdIOHandler; const ATimeOut:integer):boolean;
  143. function MakeSocks5Listen(AIOHandler: TIdIOHandler; const ATimeOut:integer):boolean;
  144. //association for UDP
  145. procedure MakeSocks5UDPAssociation(AHandle : TIdSocketHandle);
  146. procedure CloseSocks5UDPAssociation;
  147. public
  148. procedure Assign(ASource: TPersistent); override;
  149. destructor Destroy; override;
  150. procedure Bind(AIOHandler: TIdIOHandler; const AHost: string; const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  151. function Listen(AIOHandler: TIdIOHandler; const ATimeOut:integer):boolean;override;
  152. procedure OpenUDP(AHandle : TIdSocketHandle; const AHost: string = ''; const APort: TIdPort = 0; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override;
  153. function RecvFromUDP(AHandle: TIdSocketHandle; var ABuffer : TIdBytes;
  154. var VPeerIP: string; var VPeerPort: TIdPort; var VIPVersion: TIdIPVersion;
  155. AMSec: Integer = IdTimeoutDefault): Integer; override;
  156. procedure SendToUDP(AHandle: TIdSocketHandle; const AHost: string;
  157. const APort: TIdPort; const AIPVersion: TIdIPVersion; const ABuffer : TIdBytes); override;
  158. procedure CloseUDP(AHandle: TIdSocketHandle); override;
  159. published
  160. property Authentication: TSocksAuthentication read FAuthentication write FAuthentication default ID_SOCKS_AUTH;
  161. property Host;
  162. property Password;
  163. property Port default IdPORT_SOCKS;
  164. property IPVersion default ID_DEFAULT_IP_VERSION;
  165. property Username;
  166. property Version: TSocksVersion read FVersion write FVersion default ID_SOCKS_VER;
  167. property ChainedProxy;
  168. End;//TIdSocksInfo
  169. implementation
  170. uses
  171. IdResourceStringsCore, IdExceptionCore, IdIPAddress, IdStack,
  172. IdTCPClient,
  173. IdIOHandlerStack, SysUtils;
  174. { TIdSocksInfo }
  175. procedure TIdSocksInfo.Assign(ASource: TPersistent);
  176. var
  177. LSource: TIdSocksInfo;
  178. begin
  179. if ASource is TIdSocksInfo then begin
  180. LSource := TIdSocksInfo(ASource);
  181. FAuthentication := LSource.Authentication;
  182. FVersion := LSource.Version;
  183. end;
  184. // always allow TIdCustomTransparentProxy to assign its properties as well
  185. inherited Assign(ASource);
  186. end;
  187. procedure TIdSocksInfo.MakeSocks4Request(AIOHandler: TIdIOHandler; const AHost: string;
  188. const APort: TIdPort; const ARequest : Byte);
  189. var
  190. LIpAddr: String;
  191. LBufferingStarted: Boolean;
  192. begin
  193. LBufferingStarted := not AIOHandler.WriteBufferingActive;
  194. if LBufferingStarted then begin
  195. AIOHandler.WriteBufferOpen;
  196. end;
  197. try
  198. AIOHandler.Write(Byte(4)); // Version
  199. AIOHandler.Write(ARequest); // Opcode
  200. AIOHandler.Write(Word(APort)); // Port
  201. if Version = svSocks4A then begin
  202. LIpAddr := '0.0.0.1'; {Do not Localize}
  203. end else begin
  204. LIpAddr := GStack.ResolveHost(AHost,Id_IPv4);
  205. end;
  206. AIOHandler.Write(Byte(IndyStrToInt(Fetch(LIpAddr,'.'))));// IP
  207. AIOHandler.Write(Byte(IndyStrToInt(Fetch(LIpAddr,'.'))));// IP
  208. AIOHandler.Write(Byte(IndyStrToInt(Fetch(LIpAddr,'.'))));// IP
  209. AIOHandler.Write(Byte(IndyStrToInt(Fetch(LIpAddr,'.'))));// IP
  210. AIOHandler.Write(Username);
  211. AIOHandler.Write(Byte(0));// Username
  212. if Version = svSocks4A then begin
  213. AIOHandler.Write(AHost);
  214. AIOHandler.Write(Byte(0));// Host
  215. end;
  216. if LBufferingStarted then begin
  217. AIOHandler.WriteBufferClose; //flush everything
  218. end;
  219. except
  220. if LBufferingStarted then begin
  221. AIOHandler.WriteBufferCancel; //cancel everything
  222. end;
  223. raise;
  224. end;
  225. end;
  226. procedure TIdSocksInfo.MakeSocks4Connection(AIOHandler: TIdIOHandler; const AHost: string; const APort: TIdPort);
  227. var
  228. LResponse: TIdBytes;
  229. begin
  230. MakeSocks4Request(AIOHandler, AHost, APort,$01); //connect
  231. AIOHandler.ReadBytes(LResponse, 8, False);
  232. case LResponse[1] of // OpCode
  233. 90: ;// request granted, do nothing
  234. 91: raise EIdSocksRequestFailed.Create(RSSocksRequestFailed);
  235. 92: raise EIdSocksRequestServerFailed.Create(RSSocksRequestServerFailed);
  236. 93: raise EIdSocksRequestIdentFailed.Create(RSSocksRequestIdentFailed);
  237. else raise EIdSocksUnknownError.Create(RSSocksUnknownError);
  238. end;
  239. end;
  240. procedure TIdSocksInfo.MakeSocks5Request(AIOHandler: TIdIOHandler; const AHost: string; const APort: TIdPort; const ARequest : Byte; var VBuf : TIdBytes; var VLen : Integer);
  241. var
  242. LIP : TIdIPAddress;
  243. LAddr: TIdBytes;
  244. begin
  245. // Connection process
  246. VBuf[0] := $5; // socks version
  247. VBuf[1] := ARequest; //request method
  248. VBuf[2] := $0; // reserved
  249. // address type: IP V4 address: X'01' {Do not Localize}
  250. // DOMAINNAME: X'03' {Do not Localize}
  251. // IP V6 address: X'04' {Do not Localize}
  252. LIP := TIdIPAddress.MakeAddressObject(AHost);
  253. if Assigned(LIP) then
  254. begin
  255. try
  256. if LIP.AddrType = Id_IPv6 then begin
  257. VBuf[3] := $04; //IPv6 address
  258. end else begin
  259. VBuf[3] := $01; //IPv4 address
  260. end;
  261. LAddr := LIP.HToNBytes;
  262. CopyTIdBytes(LAddr, 0, VBuf, 4, Length(LAddr));
  263. VLen := 4 + Length(LAddr);
  264. finally
  265. FreeAndNil(LIP);
  266. end;
  267. end else
  268. begin
  269. LAddr := ToBytes(AHost);
  270. VBuf[3] := $3; // host name
  271. VBuf[4] := IndyMin(Length(LAddr), 255);
  272. if VBuf[4] > 0 then begin
  273. CopyTIdBytes(LAddr, 0, VBuf, 5, VBuf[4]);
  274. end;
  275. VLen := 5 + VBuf[4];
  276. end;
  277. // port
  278. CopyTIdUInt16(GStack.HostToNetwork(APort), VBuf, VLen);
  279. VLen := VLen + 2;
  280. end;
  281. procedure TIdSocksInfo.MakeSocks5Connection(AIOHandler: TIdIOHandler; const AHost: string; const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  282. var
  283. Lpos: Integer;
  284. LBuf: TIdBytes;
  285. begin
  286. AuthenticateSocks5Connection(AIOHandler);
  287. SetLength(LBuf, 255);
  288. MakeSocks5Request(AIOHandler, AHost, APort, $01, LBuf, Lpos);
  289. LBuf := ToBytes(LBuf, Lpos);
  290. AIOHandler.WriteDirect(LBuf); // send the connection packet
  291. try
  292. AIOHandler.ReadBytes(LBuf, 5, False); // Socks server replies on connect, this is the first part
  293. except
  294. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  295. end;
  296. case LBuf[1] of
  297. 0: ;// success, do nothing
  298. 1: raise EIdSocksServerGeneralError.Create(RSSocksServerGeneralError);
  299. 2: raise EIdSocksServerPermissionError.Create(RSSocksServerPermissionError);
  300. 3: raise EIdSocksServerNetUnreachableError.Create(RSSocksServerNetUnreachableError);
  301. 4: raise EIdSocksServerHostUnreachableError.Create(RSSocksServerHostUnreachableError);
  302. 5: raise EIdSocksServerConnectionRefusedError.Create(RSSocksServerConnectionRefusedError);
  303. 6: raise EIdSocksServerTTLExpiredError.Create(RSSocksServerTTLExpiredError);
  304. 7: raise EIdSocksServerCommandError.Create(RSSocksServerCommandError);
  305. 8: raise EIdSocksServerAddressError.Create(RSSocksServerAddressError);
  306. else
  307. raise EIdSocksUnknownError.Create(RSSocksUnknownError);
  308. end;
  309. // type of destination address is domain name
  310. case LBuf[3] of
  311. // IP V4
  312. 1: Lpos := 4 + 2; // 4 is for address and 2 is for port length
  313. // FQDN
  314. 3: Lpos := LBuf[4] + 2; // 2 is for port length
  315. // IP V6
  316. 4: Lpos := 16 + 2; // 16 is for address and 2 is for port length
  317. end;
  318. try
  319. // Socks server replies on connect, this is the second part
  320. // RLebeau: why -1?
  321. AIOHandler.ReadBytes(LBuf, Lpos-1, False); // just write it over the first part for now
  322. except
  323. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  324. end;
  325. end;
  326. procedure TIdSocksInfo.MakeSocks4Bind(AIOHandler: TIdIOHandler; const AHost: string; const APort: TIdPort);
  327. var
  328. LResponse: TIdBytes;
  329. LClient: TIdTcpClient;
  330. begin
  331. LClient := TIdTCPClient.Create(nil);
  332. try
  333. // SetLength(LResponse, 255);
  334. SetLength(LResponse, 8);
  335. TIdIOHandlerSocket(AIOHandler).TransparentProxy := nil;
  336. LClient.IOHandler := AIOHandler;
  337. LClient.Host := Host;
  338. LClient.Port := Port;
  339. LClient.Connect;
  340. TIdIOHandlerSocket(AIOHandler).TransparentProxy := Self;
  341. MakeSocks4Request(AIOHandler, AHost, APort, $02); //bind
  342. AIOHandler.ReadBytes(LResponse, 2, False);
  343. case LResponse[1] of // OpCode
  344. 90: ;// request granted, do nothing
  345. 91: raise EIdSocksRequestFailed.Create(RSSocksRequestFailed);
  346. 92: raise EIdSocksRequestServerFailed.Create(RSSocksRequestServerFailed);
  347. 93: raise EIdSocksRequestIdentFailed.Create(RSSocksRequestIdentFailed);
  348. else raise EIdSocksUnknownError.Create(RSSocksUnknownError);
  349. end;
  350. try
  351. // Socks server replies on connect, this is the second part
  352. AIOHandler.ReadBytes(LResponse, 6, False); //overwrite the first part for now
  353. TIdIOHandlerSocket(AIOHandler).Binding.SetBinding(BytesToIPv4Str(LResponse, 2), LResponse[0]*256+LResponse[1]);
  354. except
  355. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  356. end;
  357. finally
  358. LClient.IOHandler := nil;
  359. FreeAndNil(LClient);
  360. end;
  361. end;
  362. procedure TIdSocksInfo.MakeConnection(AIOHandler: TIdIOHandler; const AHost: string; const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  363. begin
  364. case Version of
  365. svSocks4, svSocks4A: MakeSocks4Connection(AIOHandler, AHost, APort);
  366. svSocks5: MakeSocks5Connection(AIOHandler, AHost, APort);
  367. end;
  368. end;
  369. function TIdSocksInfo.GetEnabled: Boolean;
  370. Begin
  371. Result := Version in [svSocks4, svSocks4A, svSocks5];
  372. End;//
  373. procedure TIdSocksInfo.InitComponent;
  374. begin
  375. inherited InitComponent;
  376. Authentication := ID_SOCKS_AUTH;
  377. Version := ID_SOCKS_VER;
  378. Port := IdPORT_SOCKS;
  379. FUDPSocksAssociation := TIdIOHandlerStack.Create;
  380. end;
  381. procedure TIdSocksInfo.AuthenticateSocks5Connection(
  382. AIOHandler: TIdIOHandler);
  383. var
  384. Lpos: Integer;
  385. LBuf,
  386. LUsername,
  387. LPassword : TIdBytes;
  388. LRequestedAuthMethod,
  389. LServerAuthMethod,
  390. LUsernameLen,
  391. LPasswordLen : Byte;
  392. begin
  393. // keep the compiler happy
  394. LUsername := nil;
  395. LPassword := nil;
  396. SetLength(LBuf, 3);
  397. // defined in rfc 1928
  398. if Authentication = saNoAuthentication then begin
  399. LBuf[2] := $0 // No authentication
  400. end else begin
  401. LBuf[2] := $2; // Username password authentication
  402. end;
  403. LRequestedAuthMethod := LBuf[2];
  404. LBuf[0] := $5; // socks version
  405. LBuf[1] := $1; // number of possible authentication methods
  406. AIOHandler.WriteDirect(LBuf);
  407. try
  408. AIOHandler.ReadBytes(LBuf, 2, False); // Socks server sends the selected authentication method
  409. except
  410. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  411. end;
  412. LServerAuthMethod := LBuf[1];
  413. if (LServerAuthMethod <> LRequestedAuthMethod) or (LServerAuthMethod = $FF) then begin
  414. raise EIdSocksAuthMethodError.Create(RSSocksAuthMethodError);
  415. end;
  416. // Authentication process
  417. if Authentication = saUsernamePassword then begin
  418. LUsername := ToBytes(Username);
  419. LPassword := ToBytes(Password);
  420. LUsernameLen := IndyMin(Length(LUsername), 255);
  421. LPasswordLen := IndyMin(Length(LPassword), 255);
  422. SetLength(LBuf, 3 + LUsernameLen + LPasswordLen);
  423. LBuf[0] := 1; // version of subnegotiation
  424. LBuf[1] := LUsernameLen;
  425. Lpos := 2;
  426. if LUsernameLen > 0 then begin
  427. CopyTIdBytes(LUsername, 0, LBuf, Lpos, LUsernameLen);
  428. Lpos := Lpos + LUsernameLen;
  429. end;
  430. LBuf[Lpos] := LPasswordLen;
  431. Lpos := Lpos + 1;
  432. if LPasswordLen > 0 then begin
  433. CopyTIdBytes(LPassword, 0, LBuf, Lpos, LPasswordLen);
  434. end;
  435. AIOHandler.WriteDirect(LBuf); // send the username and password
  436. try
  437. AIOHandler.ReadBytes(LBuf, 2, False); // Socks server sends the authentication status
  438. except
  439. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  440. end;
  441. if LBuf[1] <> $0 then begin
  442. raise EIdSocksAuthError.Create(RSSocksAuthError);
  443. end;
  444. end;
  445. end;
  446. procedure TIdSocksInfo.MakeSocks5Bind(AIOHandler: TIdIOHandler; const AHost: string;
  447. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  448. var
  449. Lpos: Integer;
  450. LBuf: TIdBytes;
  451. LClient: TIdTCPClient;
  452. LType : Byte;
  453. LAddress: TIdIPv6Address;
  454. LIPVersion: TIdIPVersion;
  455. begin
  456. LClient := TIdTCPClient.Create(nil);
  457. try
  458. SetLength(LBuf, 255);
  459. TIdIOHandlerSocket(AIOHandler).TransparentProxy := nil;
  460. LClient.IOHandler := AIOHandler;
  461. LClient.Host := Host;
  462. LClient.IPVersion := IPVersion;
  463. LClient.Port := Port;
  464. LClient.Connect;
  465. TIdIOHandlerSocket(AIOHandler).TransparentProxy := Self;
  466. AuthenticateSocks5Connection(AIOHandler);
  467. // Bind process
  468. MakeSocks5Request(AIOHandler, AHost, APort, $02, LBuf, LPos); //bind request
  469. //
  470. AIOHandler.Write(LBuf, LPos); // send the connection packet
  471. try
  472. AIOHandler.ReadBytes(LBuf, 4, False); // Socks server replies on connect, this is the first part
  473. except
  474. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  475. end;
  476. case LBuf[1] of
  477. 0: ;// success, do nothing
  478. 1: raise EIdSocksServerGeneralError.Create(RSSocksServerGeneralError);
  479. 2: raise EIdSocksServerPermissionError.Create(RSSocksServerPermissionError);
  480. 3: raise EIdSocksServerNetUnreachableError.Create(RSSocksServerNetUnreachableError);
  481. 4: raise EIdSocksServerHostUnreachableError.Create(RSSocksServerHostUnreachableError);
  482. 5: raise EIdSocksServerConnectionRefusedError.Create(RSSocksServerConnectionRefusedError);
  483. 6: raise EIdSocksServerTTLExpiredError.Create(RSSocksServerTTLExpiredError);
  484. 7: raise EIdSocksServerCommandError.Create(RSSocksServerCommandError);
  485. 8: raise EIdSocksServerAddressError.Create(RSSocksServerAddressError);
  486. else
  487. raise EIdSocksUnknownError.Create(RSSocksUnknownError);
  488. end;
  489. LType := LBuf[3];
  490. // type of destination address is domain name
  491. case LType of
  492. // IP V4
  493. 1: Lpos := 4 + 2; // 4 is for address and 2 is for port length
  494. // FQDN
  495. 3: Lpos := LBuf[4] + 2; // 2 is for port length
  496. // IP V6
  497. 4: LPos := 16 + 2; // 16 is for address and 2 is for port length
  498. end;
  499. try
  500. // Socks server replies on connect, this is the second part
  501. AIOHandler.ReadBytes(LBuf, Lpos, False); //overwrite the first part for now
  502. case LType of
  503. 1 : begin
  504. //IPv4
  505. TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(BytesToIPv4Str(LBuf), LBuf[4]*256+LBuf[5], Id_IPv4);
  506. end;
  507. 3 : begin
  508. LIPVersion := TIdIOHandlerSocket(AIOHandler).IPVersion;
  509. TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(GStack.ResolveHost(BytesToString(LBuf,0,LPos-2), LIPVersion), LBuf[4]*256+LBuf[5], LIPVersion);
  510. end;
  511. 4 : begin
  512. BytesToIPv6(LBuf, LAddress);
  513. TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(IPv6AddressToStr(LAddress), LBuf[16]*256+LBuf[17], Id_IPv6);
  514. end;
  515. end;
  516. except
  517. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  518. end;
  519. finally
  520. LClient.IOHandler := nil;
  521. FreeAndNil(LClient);
  522. end;
  523. end;
  524. procedure TIdSocksInfo.Bind(AIOHandler: TIdIOHandler; const AHost: string;
  525. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  526. begin
  527. case Version of
  528. svSocks4, svSocks4A: MakeSocks4Bind(AIOHandler, AHost, APort);
  529. svSocks5: MakeSocks5Bind(AIOHandler, AHost, APort, AIPVersion);
  530. end;
  531. end;
  532. function TIdSocksInfo.Listen(AIOHandler: TIdIOHandler;
  533. const ATimeOut: integer): boolean;
  534. begin
  535. Result := False;
  536. case Version of
  537. svSocks4, svSocks4A: Result := MakeSocks4Listen(AIOHandler, ATimeOut);
  538. svSocks5: Result := MakeSocks5Listen(AIOHandler, ATimeOut);
  539. end;
  540. end;
  541. function TIdSocksInfo.MakeSocks5Listen(AIOHandler: TIdIOHandler;
  542. const ATimeOut: integer): boolean;
  543. var
  544. Lpos: Integer;
  545. LBuf: TIdBytes;
  546. LType : Byte;
  547. LAddress: TIdIPv6Address;
  548. LIPVersion: TIdIPVersion;
  549. begin
  550. SetLength(LBuf, 255);
  551. Result := TIdIOHandlerSocket(AIOHandler).Binding.Readable(ATimeOut);
  552. if Result then begin
  553. AIOHandler.ReadBytes(LBuf, 4, False); // Socks server replies on connect, this is the first part
  554. case LBuf[1] of
  555. 0: ;// success, do nothing
  556. 1: raise EIdSocksServerGeneralError.Create(RSSocksServerGeneralError);
  557. 2: raise EIdSocksServerPermissionError.Create(RSSocksServerPermissionError);
  558. 3: raise EIdSocksServerNetUnreachableError.Create(RSSocksServerNetUnreachableError);
  559. 4: raise EIdSocksServerHostUnreachableError.Create(RSSocksServerHostUnreachableError);
  560. 5: raise EIdSocksServerConnectionRefusedError.Create(RSSocksServerConnectionRefusedError);
  561. 6: raise EIdSocksServerTTLExpiredError.Create(RSSocksServerTTLExpiredError);
  562. 7: raise EIdSocksServerCommandError.Create(RSSocksServerCommandError);
  563. 8: raise EIdSocksServerAddressError.Create(RSSocksServerAddressError);
  564. else
  565. raise EIdSocksUnknownError.Create(RSSocksUnknownError);
  566. end;
  567. LType := LBuf[3];
  568. // type of destination address is domain name
  569. case LType of
  570. // IP V4
  571. 1: Lpos := 4 + 2; // 4 is for address and 2 is for port length
  572. // FQDN
  573. 3: Lpos := LBuf[4] + 2; // 2 is for port length
  574. // IP V6 - 4:
  575. else
  576. Lpos := 16 + 2; // 16 is for address and 2 is for port length
  577. end;
  578. // Socks server replies on connect, this is the second part
  579. AIOHandler.ReadBytes(LBuf, Lpos, False); // just write it over the first part for now
  580. case LType of
  581. 1 : begin
  582. //IPv4
  583. TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(BytesToIPv4Str(LBuf), LBuf[4]*256+LBuf[5], Id_IPv4);
  584. end;
  585. 3 : begin
  586. //FQN
  587. LIPVersion := TIdIOHandlerSocket(AIOHandler).IPVersion;
  588. TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(GStack.ResolveHost(BytesToString(LBuf,0,LPos-2), LIPVersion), LBuf[4]*256+LBuf[5], LIPVersion);
  589. end;
  590. else begin
  591. //IPv6
  592. BytesToIPv6(LBuf, LAddress);
  593. TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(IPv6AddressToStr(LAddress), LBuf[16]*256+LBuf[17], Id_IPv6);
  594. end;
  595. end;
  596. end;
  597. end;
  598. function TIdSocksInfo.MakeSocks4Listen(AIOHandler: TIdIOHandler;
  599. const ATimeOut: integer): boolean;
  600. var
  601. LBuf: TIdBytes;
  602. begin
  603. SetLength(LBuf, 6);
  604. Result := TIdIOHandlerSocket(AIOHandler).Binding.Readable(ATimeOut);
  605. if Result then begin
  606. AIOHandler.ReadBytes(LBuf, 2, False); // Socks server replies on connect, this is the first part
  607. case LBuf[1] of // OpCode
  608. 90: ;// request granted, do nothing
  609. 91: raise EIdSocksRequestFailed.Create(RSSocksRequestFailed);
  610. 92: raise EIdSocksRequestServerFailed.Create(RSSocksRequestServerFailed);
  611. 93: raise EIdSocksRequestIdentFailed.Create(RSSocksRequestIdentFailed);
  612. else raise EIdSocksUnknownError.Create(RSSocksUnknownError);
  613. end;
  614. // Socks server replies on connect, this is the second part
  615. AIOHandler.ReadBytes(LBuf, 6, False); // just write it over the first part for now
  616. TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(BytesToIPv4Str(LBuf, 2), LBuf[0]*256+LBuf[1], Id_IPv4);
  617. end;
  618. end;
  619. procedure TIdSocksInfo.CloseSocks5UDPAssociation;
  620. begin
  621. if Assigned(FUDPSocksAssociation) then begin
  622. FUDPSocksAssociation.Close;
  623. end;
  624. end;
  625. procedure TIdSocksInfo.MakeSocks5UDPAssociation(AHandle: TIdSocketHandle);
  626. var
  627. Lpos: Integer;
  628. LBuf: TIdBytes;
  629. LIPVersion : TIdIPVersion;
  630. begin
  631. LIPVersion := Self.IPVersion;
  632. FUDPSocksAssociation.Host := Self.Host;
  633. FUDPSocksAssociation.Port := Self.Port;
  634. FUDPSocksAssociation.IPVersion := LIPVersion;
  635. FUDPSocksAssociation.Open;
  636. try
  637. SetLength(LBuf, 255);
  638. AuthenticateSocks5Connection(FUDPSocksAssociation);
  639. // Associate process
  640. //For SOCKS5 Associate, the IP address and port is the client's IP address and port which may
  641. //not be known
  642. if LIPVersion = Id_IPv4 then begin
  643. MakeSocks5Request(FUDPSocksAssociation, '0.0.0.0', 0, $03, LBuf, LPos); //associate request
  644. end else begin
  645. MakeSocks5Request(FUDPSocksAssociation, '::0', 0, $03, LBuf, LPos); //associate request
  646. end;
  647. //
  648. FUDPSocksAssociation.Write(LBuf, LPos); // send the connection packet
  649. try
  650. FUDPSocksAssociation.ReadBytes(LBuf, 2, False); // Socks server replies on connect, this is the first part )VER and RSP
  651. except
  652. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  653. end;
  654. case LBuf[1] of
  655. 0: ;// success, do nothing
  656. 1: raise EIdSocksServerGeneralError.Create(RSSocksServerGeneralError);
  657. 2: raise EIdSocksServerPermissionError.Create(RSSocksServerPermissionError);
  658. 3: raise EIdSocksServerNetUnreachableError.Create(RSSocksServerNetUnreachableError);
  659. 4: raise EIdSocksServerHostUnreachableError.Create(RSSocksServerHostUnreachableError);
  660. 5: raise EIdSocksServerConnectionRefusedError.Create(RSSocksServerConnectionRefusedError);
  661. 6: raise EIdSocksServerTTLExpiredError.Create(RSSocksServerTTLExpiredError);
  662. 7: raise EIdSocksServerCommandError.Create(RSSocksServerCommandError);
  663. 8: raise EIdSocksServerAddressError.Create(RSSocksServerAddressError);
  664. else
  665. raise EIdSocksUnknownError.Create(RSSocksUnknownError);
  666. end;
  667. FUDPSocksAssociation.ReadBytes(LBuf, 2, False); //Now get RSVD and ATYPE feilds
  668. // type of destination address is domain name
  669. case LBuf[1] of
  670. // IP V4
  671. 1: begin
  672. Lpos := 4 + 2; // 4 is for address and 2 is for port length
  673. LIPVersion := Id_IPv4;
  674. end;
  675. // FQDN
  676. 3: Lpos := LBuf[4] + 2; // 2 is for port length
  677. // IP V6
  678. 4: begin
  679. LPos := 16 + 2; // 16 is for address and 2 is for port length
  680. LIPVersion := Id_IPv6;
  681. end;
  682. end;
  683. try
  684. // Socks server replies on connect, this is the second part
  685. FUDPSocksAssociation.ReadBytes(LBuf, Lpos, False); //overwrite the first part for now
  686. AHandle.SetPeer( (FUDPSocksAssociation as TIdIOHandlerStack).Binding.PeerIP ,LBuf[4]*256+LBuf[5],LIPVersion);
  687. AHandle.Connect;
  688. except
  689. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  690. end;
  691. except
  692. FUDPSocksAssociation.Close;
  693. raise;
  694. end;
  695. end;
  696. procedure TIdSocksInfo.CloseUDP(AHandle: TIdSocketHandle);
  697. begin
  698. case Version of
  699. svSocks4, svSocks4A: raise EIdSocksUDPNotSupportedBySOCKSVersion.Create(RSSocksUDPNotSupported);
  700. svSocks5: CloseSocks5UDPAssociation;
  701. end;
  702. end;
  703. procedure TIdSocksInfo.OpenUDP(AHandle: TIdSocketHandle;
  704. const AHost: string=''; const APort: TIdPort=0; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  705. begin
  706. case Version of
  707. svSocks4, svSocks4A: raise EIdSocksUDPNotSupportedBySOCKSVersion.Create(RSSocksUDPNotSupported);
  708. svSocks5: MakeSocks5UDPAssociation(AHandle);
  709. end;
  710. end;
  711. function TIdSocksInfo.DisasmUDPReplyPacket(const APacket : TIdBytes;
  712. var VHost : String; var VPort : TIdPort; var VIPVersion: TIdIPVersion): TIdBytes;
  713. {
  714. +----+------+------+----------+----------+----------+
  715. |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
  716. +----+------+------+----------+----------+----------+
  717. | 2 | 1 | 1 | Variable | 2 | Variable |
  718. +----+------+------+----------+----------+----------+
  719. 01 2 3
  720. The fields in the UDP request header are:
  721. o RSV Reserved X'0000'
  722. o FRAG Current fragment number
  723. o ATYP address type of following addresses:
  724. o IP V4 address: X'01'
  725. o DOMAINNAME: X'03'
  726. o IP V6 address: X'04'
  727. o DST.ADDR desired destination address
  728. o DST.PORT desired destination port
  729. o DATA user data
  730. }
  731. var
  732. LLen : Integer;
  733. LIP6 : TIdIPv6Address;
  734. i : Integer;
  735. begin
  736. if Length(APacket) < 5 then begin
  737. Exit;
  738. end;
  739. // type of destination address is domain name
  740. case APacket[3] of
  741. // IP V4
  742. 1: begin
  743. LLen := 4 + 4; //4 IPv4 address len, 4- 2 reserved, 1 frag, 1 atype
  744. VHost := BytesToIPv4Str(APacket, 4);
  745. VIPVersion := Id_IPv4;
  746. end;
  747. // FQDN
  748. 3: begin
  749. LLen := APacket[4] +4; // 2 is for port length, 4 - 2 reserved, 1 frag, 1 atype
  750. if Length(APacket)< (5+LLen) then begin
  751. Exit;
  752. end;
  753. VHost := BytesToString(APacket, 5, APacket[4]);
  754. // VIPVersion is pre-initialized by the receiving socket before DisasmUDPReplyPacket() is called
  755. end;
  756. // IP V6 - 4:
  757. else begin
  758. LLen := 16 + 4; // 16 is for address, 2 is for port length, 4 - 2 reserved, 1 frag, 1 atype
  759. BytesToIPv6(APacket, LIP6, 5);
  760. for i := 0 to 7 do begin
  761. LIP6[i] := GStack.NetworkToHost(LIP6[i]);
  762. end;
  763. VHost := IPv6AddressToStr(LIP6);
  764. VIPVersion := Id_IPv6;
  765. end;
  766. end;
  767. VPort := APacket[LLen]*256 + APacket[LLen+1];
  768. LLen := LLen + 2;
  769. SetLength(Result, Length(APacket)-LLen);
  770. CopyTIdBytes(APacket, LLen, Result, 0, Length(APacket)-LLen);
  771. end;
  772. function TIdSocksInfo.MakeUDPRequestPacket(const AData: TIdBytes;
  773. const AHost : String; const APort : TIdPort) : TIdBytes;
  774. {
  775. +----+------+------+----------+----------+----------+
  776. |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
  777. +----+------+------+----------+----------+----------+
  778. | 2 | 1 | 1 | Variable | 2 | Variable |
  779. +----+------+------+----------+----------+----------+
  780. 01 2 3
  781. The fields in the UDP request header are:
  782. o RSV Reserved X'0000'
  783. o FRAG Current fragment number
  784. o ATYP address type of following addresses:
  785. o IP V4 address: X'01'
  786. o DOMAINNAME: X'03'
  787. o IP V6 address: X'04'
  788. o DST.ADDR desired destination address
  789. o DST.PORT desired destination port
  790. o DATA user data
  791. }
  792. var
  793. LLen : Integer;
  794. LIP : TIdIPAddress;
  795. LAddr: TIdBytes;
  796. begin
  797. SetLength(Result, 1024);
  798. Result[0] := 0;
  799. Result[1] := 0;
  800. Result[2] := 0; //no fragmentation - too lazy to implement it
  801. // address type: IP V4 address: X'01' {Do not Localize}
  802. // DOMAINNAME: X'03' {Do not Localize}
  803. // IP V6 address: X'04' {Do not Localize}
  804. LIP := TIdIPAddress.MakeAddressObject(AHost);
  805. if Assigned(LIP) then
  806. begin
  807. try
  808. if LIP.AddrType = Id_IPv6 then begin
  809. Result[3] := $04; //IPv6 address
  810. end else begin
  811. Result[3] := $01; //IPv4 address
  812. end;
  813. LLen := 4;
  814. LAddr := LIP.HToNBytes;
  815. CopyTIdBytes(LAddr, 0, Result, 4, Length(LAddr));
  816. LLen := LLen + Length(LAddr);
  817. finally
  818. FreeAndNil(LIP);
  819. end;
  820. end else
  821. begin
  822. LAddr := ToBytes(AHost);
  823. Result[3] := $3; // host name
  824. Result[4] := IndyMin(Length(LAddr), 255);
  825. if Result[4] > 0 then begin
  826. CopyTIdBytes(LAddr, 0, Result, 5, Result[4]);
  827. end;
  828. LLen := 5 + Result[4];
  829. end;
  830. // port
  831. CopyTIdUInt16(GStack.HostToNetwork(APort), Result, LLen);
  832. LLen := LLen + 2;
  833. //now do the rest of the packet
  834. SetLength(Result, LLen + Length(AData));
  835. CopyTIdBytes(AData, 0, Result, LLen, Length(AData));
  836. end;
  837. function TIdSocksInfo.RecvFromUDP(AHandle: TIdSocketHandle;
  838. var ABuffer : TIdBytes; var VPeerIP: string; var VPeerPort: TIdPort;
  839. var VIPVersion: TIdIPVersion; AMSec: Integer = IdTimeoutDefault): Integer;
  840. var
  841. LBuf : TIdBytes;
  842. begin
  843. case Version of
  844. svSocks4, svSocks4A: raise EIdSocksUDPNotSupportedBySOCKSVersion.Create(RSSocksUDPNotSupported);
  845. end;
  846. SetLength(LBuf, Length(ABuffer)+200);
  847. if not AHandle.Readable(AMSec) then begin
  848. Result := 0;
  849. VPeerIP := ''; {Do not Localize}
  850. VPeerPort := 0;
  851. VIPVersion := ID_DEFAULT_IP_VERSION;
  852. Exit;
  853. end;
  854. Result := AHandle.RecvFrom(LBuf, VPeerIP, VPeerPort, VIPVersion);
  855. SetLength(LBuf, Result);
  856. LBuf := DisasmUDPReplyPacket(LBuf, VPeerIP, VPeerPort, VIPVersion);
  857. Result := Length(LBuf);
  858. CopyTIdBytes(LBuf, 0, ABuffer, 0, Result);
  859. end;
  860. procedure TIdSocksInfo.SendToUDP(AHandle: TIdSocketHandle; const AHost: string;
  861. const APort: TIdPort; const AIPVersion: TIdIPVersion; const ABuffer : TIdBytes);
  862. var
  863. LBuf : TIdBytes;
  864. begin
  865. case Version of
  866. svSocks4, svSocks4A: raise EIdSocksUDPNotSupportedBySOCKSVersion.Create(RSSocksUDPNotSupported);
  867. end;
  868. LBuf := MakeUDPRequestPacket(ABuffer, AHost, APort);
  869. AHandle.Send(LBuf, 0);
  870. end;
  871. destructor TIdSocksInfo.Destroy;
  872. begin
  873. FreeAndNil(FUDPSocksAssociation);
  874. inherited Destroy;
  875. end;
  876. end.