使用Indy TIdHTTPProxyServer连接到i2p站点时出现问题

时间:2015-11-20 10:12:48

标签: delphi proxy indy freepascal indy10

我正在开发一个类似于浏览器pac文件的代理交换系统。我设法过滤并将大多数请求重定向到正确的IOhandler和Socks代理。

  

我在Firefox中使用的连接设置是

     

"手动代理配置:"
  " HTTP代理127.0.0.1端口8080"
  "将此代理服务器用于所有协议"被勾选。

     

"远程DNS"被勾选。

我非常确定远程DNS不是问题所在,因为如果我将Firefox的HTTP端口设置为4444.I2P工作正常。

问题似乎在ChainProxy功能中。而不是从HTTPProxyServer传递标头:TIdHTTPProxyServer代理主机' 127.0.0.1'代理端口' 8080'到链:TIdConnectThroughHttpProxy;代理主机' 127.0.0.1'代理端口' 4444'它对i2p网站名称进行DNS请求,当然这是失败的。 我究竟做错了什么? 谢谢。

function Standard_IO(AContext: TIdHTTPProxyServerContext): TIdIOHandler;
var
  StackIO: TIdIOHandlerStack;
begin
  StackIO:=TIdIOHandlerStack.Create(AContext.OutboundClient);
  Result:=StackIO;
end;

function SSL_IO(AContext: TIdHTTPProxyServerContext): TIdIOHandler;
var
  SSLStackIO: TIdSSLIOHandlerSocketOpenSSL;
begin
  SSLStackIO:=TIdSSLIOHandlerSocketOpenSSL.Create(AContext.OutboundClient);
  SSLStackIO.SSLOptions.Mode:=sslmUnassigned;
  SSLStackIO.SSLOptions.Method:=sslvTLSv1_2;
  SSLStackIO.SSLOptions.SSLVersions:=[sslvSSLv2,sslvSSLv3,sslvTLSv1,sslvTLSv1_1,sslvTLSv1_2];
  SSLStackIO.SSLOptions.VerifyMode:=[];
  SSLStackIO.PassThrough:=True;
  Result:=SSLStackIO;
end;

function SocksProxy(AContext: TIdHTTPProxyServerContext; Host: String; Port: TIdPort; Version: TSocksVersion):  TIdCustomTransparentProxy;
var
  Socks: TIdSocksInfo;
begin
  AContext.OutboundClient.IOHandler:=Standard_IO(AContext);
  Socks:=TIdSocksInfo.Create(AContext.OutboundClient);
  Socks.Host:=Host;
  Socks.Port:=Port;
  Socks.Authentication:=saNoAuthentication;
  Socks.Version:=Version;
  Result:=Socks;
end;

function ChainProxy(AContext: TIdHTTPProxyServerContext; Host: String; Port: TIdPort): TIdCustomTransparentProxy;
var
  Chain: TIdConnectThroughHttpProxy;
begin
   AContext.OutboundClient.IOHandler:=Standard_IO(AContext);
   Chain:=TIdConnectThroughHttpProxy.Create(AContext.OutboundClient);
   Chain.Host:=Host;
   Chain.Port:=Port;
   Chain.Enabled:=True;
   Result:=Chain;
end;  

procedure TForm1.HTTPProxyServerHTTPBeforeCommand(AContext: TIdHTTPProxyServerContext);
begin
  case SwitchProxy(AContext) of
    0: AContext.OutboundClient.IOHandler:=Standard_IO(AContext);  // http://*
    1: AContext.OutboundClient.IOHandler:=SSL_IO(AContext);       // https://*:443
    2: AContext.OutboundClient.Socket.TransparentProxy:=SocksProxy(AContext, '127.0.0.1', 9150, svSocks5);  // *.onion
    3: AContext.OutboundClient.Socket.TransparentProxy:=ChainProxy(AContext, '127.0.0.1', 4444);            // *.i2p
   end;
end;     

1 个答案:

答案 0 :(得分:0)

如果连接到TIdHTTPProxyServer的HTTP客户端请求.i2p主机名(并且可能是SwitchProxy()在返回3时查找的内容),则{{1}将要求OutboundClient.IOHandler与运行在127.0.0.1:4444的HTTP代理建立套接字连接,并向其发送命令以从HTTP客户端的原始TIdConnectThroughHttpProxy请求连接到主机名和端口。然后,HTTP代理必须先使用DNS将.i2p主机名解析为IP,然后才能与该主机建立套接字连接并返回.i2p的回复。 TIdConnectThroughHttpProxy以相同的方式运作。

FireFox中的TIdSocksInfo选项控制FireFox本身在连接到代理之前是否将主机名解析为IP,或者它是否要求代理执行解析:

  • 如果Remote DNS关闭,FireFox将在本地解析IP,然后要求代理连接到该IP(Indy在连接到主机名时不会执行此操作)。

  • 如果启用Remote DNS,FireFox会将主机名发送给代理并要求其解析IP(Indy在连接主机名时执行此操作)。

由于您的SOCKS / HTTP代理与Remote DNS在同一台计算机上运行,​​如果计算机无法将TIdHTTPProxyServer主机名解析为IP,则说明您的计算机存在DNS问题,或者代理的配置。这不是您的.i2p代码的问题。

话虽这么说,你可以模仿FireFox在TIdHTTPProxyServer关闭时所做的事情。将主机名本地解析为IP的最简单方法是在Remote DNS单元中使用Indy的GIdStack.ResolveHost()函数。这依赖于本地操作系统来执行实际的DNS查找。如果您想使用您选择的外部DNS服务器(例如公共互联网上的任意数量的免费开放DNS服务器,如8.8.8.8或8.8.4.4的Google的DNS服务器)执行DNS查找,您可以使用Indy的{ {1}}组件。

无论哪种方式,您都可以让IdStack处理程序检索TIdDNSResolver属性的值(从HTTP客户端的原始请求中的URL初始化),如果它不是IP然后手动将其解析为IP并在退出处理程序之前将其分配回OnBeforeCommand属性。所有后续链式代理请求都将跳过服务器端DNS查找并按原样连接到IP。