IdSocks.pas 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046
  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. // RLebeau - why is this using WriteDirect() instead of Write()?
  290. AIOHandler.WriteDirect(LBuf, Lpos); // 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. try
  338. LClient.Host := Host;
  339. LClient.Port := Port;
  340. LClient.Connect;
  341. TIdIOHandlerSocket(AIOHandler).TransparentProxy := Self;
  342. MakeSocks4Request(AIOHandler, AHost, APort, $02); //bind
  343. AIOHandler.ReadBytes(LResponse, 2, False);
  344. case LResponse[1] of // OpCode
  345. 90: ;// request granted, do nothing
  346. 91: raise EIdSocksRequestFailed.Create(RSSocksRequestFailed);
  347. 92: raise EIdSocksRequestServerFailed.Create(RSSocksRequestServerFailed);
  348. 93: raise EIdSocksRequestIdentFailed.Create(RSSocksRequestIdentFailed);
  349. else raise EIdSocksUnknownError.Create(RSSocksUnknownError);
  350. end;
  351. try
  352. // Socks server replies on connect, this is the second part
  353. AIOHandler.ReadBytes(LResponse, 6, False); //overwrite the first part for now
  354. TIdIOHandlerSocket(AIOHandler).Binding.SetBinding(BytesToIPv4Str(LResponse, 2), LResponse[0]*256+LResponse[1]);
  355. except
  356. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  357. end;
  358. finally
  359. LClient.IOHandler := nil;
  360. end;
  361. finally
  362. FreeAndNil(LClient);
  363. end;
  364. end;
  365. procedure TIdSocksInfo.MakeConnection(AIOHandler: TIdIOHandler; const AHost: string; const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  366. begin
  367. case Version of
  368. svSocks4, svSocks4A: MakeSocks4Connection(AIOHandler, AHost, APort);
  369. svSocks5: MakeSocks5Connection(AIOHandler, AHost, APort);
  370. end;
  371. end;
  372. function TIdSocksInfo.GetEnabled: Boolean;
  373. Begin
  374. Result := Version in [svSocks4, svSocks4A, svSocks5];
  375. End;//
  376. procedure TIdSocksInfo.InitComponent;
  377. begin
  378. inherited InitComponent;
  379. Authentication := ID_SOCKS_AUTH;
  380. Version := ID_SOCKS_VER;
  381. Port := IdPORT_SOCKS;
  382. FUDPSocksAssociation := TIdIOHandlerStack.Create;
  383. end;
  384. procedure TIdSocksInfo.AuthenticateSocks5Connection(
  385. AIOHandler: TIdIOHandler);
  386. var
  387. Lpos: Integer;
  388. LBuf,
  389. LUsername,
  390. LPassword : TIdBytes;
  391. LRequestedAuthMethod,
  392. LServerAuthMethod,
  393. LUsernameLen,
  394. LPasswordLen : Byte;
  395. begin
  396. // keep the compiler happy
  397. LUsername := nil;
  398. LPassword := nil;
  399. SetLength(LBuf, 3);
  400. // defined in rfc 1928
  401. if Authentication = saNoAuthentication then begin
  402. LRequestedAuthMethod := $0; // No authentication
  403. end else begin
  404. LRequestedAuthMethod := $2; // Username password authentication
  405. end;
  406. LBuf[0] := $5; // socks version
  407. LBuf[1] := $1; // number of possible authentication methods
  408. LBuf[2] := LRequestedAuthMethod;
  409. // RLebeau - why is this using WriteDirect() instead of Write()?
  410. AIOHandler.WriteDirect(LBuf);
  411. try
  412. AIOHandler.ReadBytes(LBuf, 2, False); // Socks server sends the selected authentication method
  413. except
  414. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  415. end;
  416. LServerAuthMethod := LBuf[1];
  417. if (LServerAuthMethod <> LRequestedAuthMethod) or (LServerAuthMethod = $FF) then begin
  418. raise EIdSocksAuthMethodError.Create(RSSocksAuthMethodError);
  419. end;
  420. // Authentication process
  421. if Authentication = saUsernamePassword then begin
  422. LUsername := ToBytes(Username);
  423. LPassword := ToBytes(Password);
  424. LUsernameLen := IndyMin(Length(LUsername), 255);
  425. LPasswordLen := IndyMin(Length(LPassword), 255);
  426. SetLength(LBuf, 3 + LUsernameLen + LPasswordLen);
  427. LBuf[0] := 1; // version of subnegotiation
  428. LBuf[1] := LUsernameLen;
  429. Lpos := 2;
  430. if LUsernameLen > 0 then begin
  431. CopyTIdBytes(LUsername, 0, LBuf, Lpos, LUsernameLen);
  432. Inc(Lpos, LUsernameLen);
  433. end;
  434. LBuf[Lpos] := LPasswordLen;
  435. Inc(Lpos);
  436. if LPasswordLen > 0 then begin
  437. CopyTIdBytes(LPassword, 0, LBuf, Lpos, LPasswordLen);
  438. end;
  439. // RLebeau - why is this using WriteDirect() instead of Write()?
  440. AIOHandler.WriteDirect(LBuf); // send the username and password
  441. try
  442. AIOHandler.ReadBytes(LBuf, 2, False); // Socks server sends the authentication status
  443. except
  444. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  445. end;
  446. if LBuf[1] <> $0 then begin
  447. raise EIdSocksAuthError.Create(RSSocksAuthError);
  448. end;
  449. end;
  450. end;
  451. procedure TIdSocksInfo.MakeSocks5Bind(AIOHandler: TIdIOHandler; const AHost: string;
  452. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  453. var
  454. Lpos: Integer;
  455. LBuf: TIdBytes;
  456. LClient: TIdTCPClient;
  457. LType : Byte;
  458. LAddress: TIdIPv6Address;
  459. LIPVersion: TIdIPVersion;
  460. begin
  461. LClient := TIdTCPClient.Create(nil);
  462. try
  463. SetLength(LBuf, 255);
  464. TIdIOHandlerSocket(AIOHandler).TransparentProxy := nil;
  465. LClient.IOHandler := AIOHandler;
  466. try
  467. LClient.Host := Host;
  468. LClient.IPVersion := IPVersion;
  469. LClient.Port := Port;
  470. LClient.Connect;
  471. TIdIOHandlerSocket(AIOHandler).TransparentProxy := Self;
  472. AuthenticateSocks5Connection(AIOHandler);
  473. // Bind process
  474. MakeSocks5Request(AIOHandler, AHost, APort, $02, LBuf, LPos); //bind request
  475. //
  476. AIOHandler.Write(LBuf, LPos); // send the connection packet
  477. try
  478. AIOHandler.ReadBytes(LBuf, 4, False); // Socks server replies on connect, this is the first part
  479. except
  480. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  481. end;
  482. case LBuf[1] of
  483. 0: ;// success, do nothing
  484. 1: raise EIdSocksServerGeneralError.Create(RSSocksServerGeneralError);
  485. 2: raise EIdSocksServerPermissionError.Create(RSSocksServerPermissionError);
  486. 3: raise EIdSocksServerNetUnreachableError.Create(RSSocksServerNetUnreachableError);
  487. 4: raise EIdSocksServerHostUnreachableError.Create(RSSocksServerHostUnreachableError);
  488. 5: raise EIdSocksServerConnectionRefusedError.Create(RSSocksServerConnectionRefusedError);
  489. 6: raise EIdSocksServerTTLExpiredError.Create(RSSocksServerTTLExpiredError);
  490. 7: raise EIdSocksServerCommandError.Create(RSSocksServerCommandError);
  491. 8: raise EIdSocksServerAddressError.Create(RSSocksServerAddressError);
  492. else
  493. raise EIdSocksUnknownError.Create(RSSocksUnknownError);
  494. end;
  495. LType := LBuf[3];
  496. // type of destination address is domain name
  497. case LType of
  498. // IP V4
  499. 1: Lpos := 4 + 2; // 4 is for address and 2 is for port length
  500. // FQDN
  501. 3: Lpos := LBuf[4] + 2; // 2 is for port length
  502. // IP V6
  503. 4: LPos := 16 + 2; // 16 is for address and 2 is for port length
  504. end;
  505. try
  506. // Socks server replies on connect, this is the second part
  507. AIOHandler.ReadBytes(LBuf, Lpos, False); //overwrite the first part for now
  508. case LType of
  509. 1 : begin
  510. //IPv4
  511. TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(BytesToIPv4Str(LBuf), LBuf[4]*256+LBuf[5], Id_IPv4);
  512. end;
  513. 3 : begin
  514. LIPVersion := TIdIOHandlerSocket(AIOHandler).IPVersion;
  515. TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(GStack.ResolveHost(BytesToString(LBuf,0,LPos-2), LIPVersion), LBuf[4]*256+LBuf[5], LIPVersion);
  516. end;
  517. 4 : begin
  518. BytesToIPv6(LBuf, LAddress);
  519. TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(IPv6AddressToStr(LAddress), LBuf[16]*256+LBuf[17], Id_IPv6);
  520. end;
  521. end;
  522. except
  523. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  524. end;
  525. finally
  526. LClient.IOHandler := nil;
  527. end;
  528. finally
  529. FreeAndNil(LClient);
  530. end;
  531. end;
  532. procedure TIdSocksInfo.Bind(AIOHandler: TIdIOHandler; const AHost: string;
  533. const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  534. begin
  535. case Version of
  536. svSocks4, svSocks4A: MakeSocks4Bind(AIOHandler, AHost, APort);
  537. svSocks5: MakeSocks5Bind(AIOHandler, AHost, APort, AIPVersion);
  538. end;
  539. end;
  540. function TIdSocksInfo.Listen(AIOHandler: TIdIOHandler;
  541. const ATimeOut: integer): boolean;
  542. begin
  543. Result := False;
  544. case Version of
  545. svSocks4, svSocks4A: Result := MakeSocks4Listen(AIOHandler, ATimeOut);
  546. svSocks5: Result := MakeSocks5Listen(AIOHandler, ATimeOut);
  547. end;
  548. end;
  549. function TIdSocksInfo.MakeSocks5Listen(AIOHandler: TIdIOHandler;
  550. const ATimeOut: integer): boolean;
  551. var
  552. Lpos: Integer;
  553. LBuf: TIdBytes;
  554. LType : Byte;
  555. LAddress: TIdIPv6Address;
  556. LIPVersion: TIdIPVersion;
  557. begin
  558. SetLength(LBuf, 255);
  559. Result := TIdIOHandlerSocket(AIOHandler).Binding.Readable(ATimeOut);
  560. if Result then begin
  561. AIOHandler.ReadBytes(LBuf, 4, False); // Socks server replies on connect, this is the first part
  562. case LBuf[1] of
  563. 0: ;// success, do nothing
  564. 1: raise EIdSocksServerGeneralError.Create(RSSocksServerGeneralError);
  565. 2: raise EIdSocksServerPermissionError.Create(RSSocksServerPermissionError);
  566. 3: raise EIdSocksServerNetUnreachableError.Create(RSSocksServerNetUnreachableError);
  567. 4: raise EIdSocksServerHostUnreachableError.Create(RSSocksServerHostUnreachableError);
  568. 5: raise EIdSocksServerConnectionRefusedError.Create(RSSocksServerConnectionRefusedError);
  569. 6: raise EIdSocksServerTTLExpiredError.Create(RSSocksServerTTLExpiredError);
  570. 7: raise EIdSocksServerCommandError.Create(RSSocksServerCommandError);
  571. 8: raise EIdSocksServerAddressError.Create(RSSocksServerAddressError);
  572. else
  573. raise EIdSocksUnknownError.Create(RSSocksUnknownError);
  574. end;
  575. LType := LBuf[3];
  576. // type of destination address is domain name
  577. case LType of
  578. // IP V4
  579. 1: Lpos := 4 + 2; // 4 is for address and 2 is for port length
  580. // FQDN
  581. 3: Lpos := LBuf[4] + 2; // 2 is for port length
  582. // IP V6 - 4:
  583. else
  584. Lpos := 16 + 2; // 16 is for address and 2 is for port length
  585. end;
  586. // Socks server replies on connect, this is the second part
  587. AIOHandler.ReadBytes(LBuf, Lpos, False); // just write it over the first part for now
  588. case LType of
  589. 1 : begin
  590. //IPv4
  591. TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(BytesToIPv4Str(LBuf), LBuf[4]*256+LBuf[5], Id_IPv4);
  592. end;
  593. 3 : begin
  594. //FQN
  595. LIPVersion := TIdIOHandlerSocket(AIOHandler).IPVersion;
  596. TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(GStack.ResolveHost(BytesToString(LBuf,0,LPos-2), LIPVersion), LBuf[4]*256+LBuf[5], LIPVersion);
  597. end;
  598. else begin
  599. //IPv6
  600. BytesToIPv6(LBuf, LAddress);
  601. TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(IPv6AddressToStr(LAddress), LBuf[16]*256+LBuf[17], Id_IPv6);
  602. end;
  603. end;
  604. end;
  605. end;
  606. function TIdSocksInfo.MakeSocks4Listen(AIOHandler: TIdIOHandler;
  607. const ATimeOut: integer): boolean;
  608. var
  609. LBuf: TIdBytes;
  610. begin
  611. SetLength(LBuf, 6);
  612. Result := TIdIOHandlerSocket(AIOHandler).Binding.Readable(ATimeOut);
  613. if Result then begin
  614. AIOHandler.ReadBytes(LBuf, 2, False); // Socks server replies on connect, this is the first part
  615. case LBuf[1] of // OpCode
  616. 90: ;// request granted, do nothing
  617. 91: raise EIdSocksRequestFailed.Create(RSSocksRequestFailed);
  618. 92: raise EIdSocksRequestServerFailed.Create(RSSocksRequestServerFailed);
  619. 93: raise EIdSocksRequestIdentFailed.Create(RSSocksRequestIdentFailed);
  620. else raise EIdSocksUnknownError.Create(RSSocksUnknownError);
  621. end;
  622. // Socks server replies on connect, this is the second part
  623. AIOHandler.ReadBytes(LBuf, 6, False); // just write it over the first part for now
  624. TIdIOHandlerSocket(AIOHandler).Binding.SetPeer(BytesToIPv4Str(LBuf, 2), LBuf[0]*256+LBuf[1], Id_IPv4);
  625. end;
  626. end;
  627. procedure TIdSocksInfo.CloseSocks5UDPAssociation;
  628. begin
  629. if Assigned(FUDPSocksAssociation) then begin
  630. FUDPSocksAssociation.Close;
  631. end;
  632. end;
  633. procedure TIdSocksInfo.MakeSocks5UDPAssociation(AHandle: TIdSocketHandle);
  634. var
  635. Lpos: Integer;
  636. LBuf: TIdBytes;
  637. LIPVersion : TIdIPVersion;
  638. begin
  639. LIPVersion := Self.IPVersion;
  640. FUDPSocksAssociation.Host := Self.Host;
  641. FUDPSocksAssociation.Port := Self.Port;
  642. FUDPSocksAssociation.IPVersion := LIPVersion;
  643. FUDPSocksAssociation.Open;
  644. try
  645. SetLength(LBuf, 255);
  646. AuthenticateSocks5Connection(FUDPSocksAssociation);
  647. // Associate process
  648. //For SOCKS5 Associate, the IP address and port is the client's IP address and port which may
  649. //not be known
  650. // TODO: if the passed TIdSocketHandle is already bound locally, send its IP/Port...
  651. {
  652. if (AHandle.IP <> '') and (AHandle.Port <> 0) then begin
  653. MakeSocks5Request(FUDPSocksAssociation, AHandle.IP, AHandle.Port, $03, LBuf, LPos); //associate request
  654. end else begin
  655. }
  656. MakeSocks5Request(FUDPSocksAssociation, iif(LIPVersion = Id_IPv4, '0.0.0.0', '::0'), 0, $03, LBuf, LPos); //associate request
  657. //end;
  658. //
  659. FUDPSocksAssociation.Write(LBuf, LPos); // send the connection packet
  660. try
  661. FUDPSocksAssociation.ReadBytes(LBuf, 2, False); // Socks server replies on connect, this is the first part )VER and RSP
  662. except
  663. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  664. end;
  665. case LBuf[1] of
  666. 0: ;// success, do nothing
  667. 1: raise EIdSocksServerGeneralError.Create(RSSocksServerGeneralError);
  668. 2: raise EIdSocksServerPermissionError.Create(RSSocksServerPermissionError);
  669. 3: raise EIdSocksServerNetUnreachableError.Create(RSSocksServerNetUnreachableError);
  670. 4: raise EIdSocksServerHostUnreachableError.Create(RSSocksServerHostUnreachableError);
  671. 5: raise EIdSocksServerConnectionRefusedError.Create(RSSocksServerConnectionRefusedError);
  672. 6: raise EIdSocksServerTTLExpiredError.Create(RSSocksServerTTLExpiredError);
  673. 7: raise EIdSocksServerCommandError.Create(RSSocksServerCommandError);
  674. 8: raise EIdSocksServerAddressError.Create(RSSocksServerAddressError);
  675. else
  676. raise EIdSocksUnknownError.Create(RSSocksUnknownError);
  677. end;
  678. FUDPSocksAssociation.ReadBytes(LBuf, 2, False); //Now get RSVD and ATYPE fields
  679. // type of destination address is domain name
  680. case LBuf[1] of
  681. // IP V4
  682. 1: begin
  683. Lpos := 4 + 2; // 4 is for address and 2 is for port length
  684. LIPVersion := Id_IPv4;
  685. end;
  686. // FQDN
  687. 3: begin
  688. Lpos := LBuf[4] + 2; // 2 is for port length
  689. end;
  690. // IP V6
  691. 4: begin
  692. LPos := 16 + 2; // 16 is for address and 2 is for port length
  693. LIPVersion := Id_IPv6;
  694. end;
  695. end;
  696. try
  697. // Socks server replies on connect, this is the second part
  698. FUDPSocksAssociation.ReadBytes(LBuf, Lpos, False); //overwrite the first part for now
  699. AHandle.SetPeer( (FUDPSocksAssociation as TIdIOHandlerStack).Binding.PeerIP, LBuf[4]*256+LBuf[5], LIPVersion);
  700. AHandle.Connect;
  701. except
  702. IndyRaiseOuterException(EIdSocksServerRespondError.Create(RSSocksServerRespondError));
  703. end;
  704. except
  705. FUDPSocksAssociation.Close;
  706. raise;
  707. end;
  708. end;
  709. procedure TIdSocksInfo.CloseUDP(AHandle: TIdSocketHandle);
  710. begin
  711. case Version of
  712. svSocks4, svSocks4A: raise EIdSocksUDPNotSupportedBySOCKSVersion.Create(RSSocksUDPNotSupported);
  713. svSocks5: CloseSocks5UDPAssociation;
  714. end;
  715. end;
  716. procedure TIdSocksInfo.OpenUDP(AHandle: TIdSocketHandle;
  717. const AHost: string=''; const APort: TIdPort=0; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION);
  718. begin
  719. case Version of
  720. svSocks4, svSocks4A: raise EIdSocksUDPNotSupportedBySOCKSVersion.Create(RSSocksUDPNotSupported);
  721. svSocks5: MakeSocks5UDPAssociation(AHandle);
  722. end;
  723. end;
  724. function TIdSocksInfo.DisasmUDPReplyPacket(const APacket : TIdBytes;
  725. var VHost : String; var VPort : TIdPort; var VIPVersion: TIdIPVersion): TIdBytes;
  726. {
  727. +----+------+------+----------+----------+----------+
  728. |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
  729. +----+------+------+----------+----------+----------+
  730. | 2 | 1 | 1 | Variable | 2 | Variable |
  731. +----+------+------+----------+----------+----------+
  732. 01 2 3
  733. The fields in the UDP request header are:
  734. o RSV Reserved X'0000'
  735. o FRAG Current fragment number
  736. o ATYP address type of following addresses:
  737. o IP V4 address: X'01'
  738. o DOMAINNAME: X'03'
  739. o IP V6 address: X'04'
  740. o DST.ADDR desired destination address
  741. o DST.PORT desired destination port
  742. o DATA user data
  743. }
  744. var
  745. LLen : Integer;
  746. LIP6 : TIdIPv6Address;
  747. i : Integer;
  748. begin
  749. if Length(APacket) < 5 then begin
  750. Exit;
  751. end;
  752. // type of destination address is domain name
  753. case APacket[3] of
  754. // IP V4
  755. 1: begin
  756. LLen := 4 + 4; //4 IPv4 address len, 4- 2 reserved, 1 frag, 1 atype
  757. VHost := BytesToIPv4Str(APacket, 4);
  758. VIPVersion := Id_IPv4;
  759. end;
  760. // FQDN
  761. 3: begin
  762. LLen := APacket[4] +4; // 2 is for port length, 4 - 2 reserved, 1 frag, 1 atype
  763. if Length(APacket)< (5+LLen) then begin
  764. Exit;
  765. end;
  766. VHost := BytesToString(APacket, 5, APacket[4]);
  767. // VIPVersion is pre-initialized by the receiving socket before DisasmUDPReplyPacket() is called
  768. end;
  769. // IP V6 - 4:
  770. else begin
  771. LLen := 16 + 4; // 16 is for address, 2 is for port length, 4 - 2 reserved, 1 frag, 1 atype
  772. BytesToIPv6(APacket, LIP6, 5);
  773. for i := 0 to 7 do begin
  774. LIP6[i] := GStack.NetworkToHost(LIP6[i]);
  775. end;
  776. VHost := IPv6AddressToStr(LIP6);
  777. VIPVersion := Id_IPv6;
  778. end;
  779. end;
  780. VPort := APacket[LLen]*256 + APacket[LLen+1];
  781. LLen := LLen + 2;
  782. SetLength(Result, Length(APacket)-LLen);
  783. CopyTIdBytes(APacket, LLen, Result, 0, Length(APacket)-LLen);
  784. end;
  785. function TIdSocksInfo.MakeUDPRequestPacket(const AData: TIdBytes;
  786. const AHost : String; const APort : TIdPort) : TIdBytes;
  787. {
  788. +----+------+------+----------+----------+----------+
  789. |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
  790. +----+------+------+----------+----------+----------+
  791. | 2 | 1 | 1 | Variable | 2 | Variable |
  792. +----+------+------+----------+----------+----------+
  793. 01 2 3
  794. The fields in the UDP request header are:
  795. o RSV Reserved X'0000'
  796. o FRAG Current fragment number
  797. o ATYP address type of following addresses:
  798. o IP V4 address: X'01'
  799. o DOMAINNAME: X'03'
  800. o IP V6 address: X'04'
  801. o DST.ADDR desired destination address
  802. o DST.PORT desired destination port
  803. o DATA user data
  804. }
  805. var
  806. LLen : Integer;
  807. LIP : TIdIPAddress;
  808. LAddr: TIdBytes;
  809. begin
  810. SetLength(Result, 1024);
  811. Result[0] := 0;
  812. Result[1] := 0;
  813. Result[2] := 0; //no fragmentation - too lazy to implement it
  814. // address type: IP V4 address: X'01' {Do not Localize}
  815. // DOMAINNAME: X'03' {Do not Localize}
  816. // IP V6 address: X'04' {Do not Localize}
  817. LIP := TIdIPAddress.MakeAddressObject(AHost);
  818. if Assigned(LIP) then
  819. begin
  820. try
  821. if LIP.AddrType = Id_IPv6 then begin
  822. Result[3] := $04; //IPv6 address
  823. end else begin
  824. Result[3] := $01; //IPv4 address
  825. end;
  826. LLen := 4;
  827. LAddr := LIP.HToNBytes;
  828. CopyTIdBytes(LAddr, 0, Result, 4, Length(LAddr));
  829. LLen := LLen + Length(LAddr);
  830. finally
  831. FreeAndNil(LIP);
  832. end;
  833. end else
  834. begin
  835. LAddr := ToBytes(AHost);
  836. Result[3] := $3; // host name
  837. Result[4] := IndyMin(Length(LAddr), 255);
  838. if Result[4] > 0 then begin
  839. CopyTIdBytes(LAddr, 0, Result, 5, Result[4]);
  840. end;
  841. LLen := 5 + Result[4];
  842. end;
  843. // port
  844. CopyTIdUInt16(GStack.HostToNetwork(APort), Result, LLen);
  845. LLen := LLen + 2;
  846. //now do the rest of the packet
  847. SetLength(Result, LLen + Length(AData));
  848. CopyTIdBytes(AData, 0, Result, LLen, Length(AData));
  849. end;
  850. function TIdSocksInfo.RecvFromUDP(AHandle: TIdSocketHandle;
  851. var ABuffer : TIdBytes; var VPeerIP: string; var VPeerPort: TIdPort;
  852. var VIPVersion: TIdIPVersion; AMSec: Integer = IdTimeoutDefault): Integer;
  853. var
  854. LBuf : TIdBytes;
  855. begin
  856. case Version of
  857. svSocks4, svSocks4A: raise EIdSocksUDPNotSupportedBySOCKSVersion.Create(RSSocksUDPNotSupported);
  858. end;
  859. if not AHandle.Readable(AMSec) then begin
  860. Result := 0;
  861. VPeerIP := ''; {Do not Localize}
  862. VPeerPort := 0;
  863. VIPVersion := ID_DEFAULT_IP_VERSION;
  864. Exit;
  865. end;
  866. SetLength(LBuf, Length(ABuffer)+200);
  867. Result := AHandle.RecvFrom(LBuf, VPeerIP, VPeerPort, VIPVersion);
  868. SetLength(LBuf, Result);
  869. LBuf := DisasmUDPReplyPacket(LBuf, VPeerIP, VPeerPort, VIPVersion);
  870. Result := Length(LBuf);
  871. CopyTIdBytes(LBuf, 0, ABuffer, 0, Result);
  872. end;
  873. procedure TIdSocksInfo.SendToUDP(AHandle: TIdSocketHandle; const AHost: string;
  874. const APort: TIdPort; const AIPVersion: TIdIPVersion; const ABuffer : TIdBytes);
  875. var
  876. LBuf : TIdBytes;
  877. begin
  878. case Version of
  879. svSocks4, svSocks4A: raise EIdSocksUDPNotSupportedBySOCKSVersion.Create(RSSocksUDPNotSupported);
  880. end;
  881. LBuf := MakeUDPRequestPacket(ABuffer, AHost, APort);
  882. AHandle.Send(LBuf, 0);
  883. end;
  884. destructor TIdSocksInfo.Destroy;
  885. begin
  886. FreeAndNil(FUDPSocksAssociation);
  887. inherited Destroy;
  888. end;
  889. end.