如何在Java中覆盖HTTP连接中的DNS

如何在Java中覆盖HTTP连接中的DNS,java,https,Java,Https,Curl有一个功能,可以手动指定解析主机的IP地址。例如: curl https://google.com --resolve "google.com:443:173.194.72.113" 这在使用HTTPS时特别有用。如果只是一个HTTP请求,我可以通过直接指定IP地址并添加主机头来实现同样的目的。但在HTTPS中,这将中断连接,因为SSL证书主机将与IP地址而不是主机头进行比较 我的问题是,如何在Java中实现同样的功能?如果使用Apache,您可以创建一个自定义DNS解析程序来检测要重

Curl有一个功能,可以手动指定解析主机的IP地址。例如:

curl https://google.com --resolve "google.com:443:173.194.72.113"
这在使用HTTPS时特别有用。如果只是一个HTTP请求,我可以通过直接指定IP地址并添加主机头来实现同样的目的。但在HTTPS中,这将中断连接,因为SSL证书主机将与IP地址而不是主机头进行比较

我的问题是,如何在Java中实现同样的功能?

如果使用Apache,您可以创建一个自定义DNS解析程序来检测要重定向的主机,然后提供一个替代IP地址

注意:仅更改HTTPS请求的主机头不起作用。会的 抛出“javax.net.ssl.SSLPeerUnverifiedException”,强迫您信任坏消息 证书,阻止SNI工作等等,所以真的不是一个选项。A. 自定义DnsResolver是我找到的唯一一种让这些请求正常工作的干净方法 在Java中使用HTTPS

例如:

/* Custom DNS resolver */
DnsResolver dnsResolver = new SystemDefaultDnsResolver() {
    @Override
    public InetAddress[] resolve(final String host) throws UnknownHostException {
        if (host.equalsIgnoreCase("my.host.com")) {
            /* If we match the host we're trying to talk to, 
               return the IP address we want, not what is in DNS */
            return new InetAddress[] { InetAddress.getByName("127.0.0.1") };
        } else {
            /* Else, resolve it as we would normally */
            return super.resolve(host);
        }
    }
};

/* HttpClientConnectionManager allows us to use custom DnsResolver */
BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager(
    /* We're forced to create a SocketFactory Registry.  Passing null
       doesn't force a default Registry, so we re-invent the wheel. */
    RegistryBuilder.<ConnectionSocketFactory>create()
        .register("http", PlainConnectionSocketFactory.getSocketFactory())
        .register("https", SSLConnectionSocketFactory.getSocketFactory())
        .build(), 
    null, /* Default ConnectionFactory */ 
    null, /* Default SchemePortResolver */ 
    dnsResolver  /* Our DnsResolver */
    );

/* build HttpClient that will use our DnsResolver */
HttpClient httpClient = HttpClientBuilder.create()
        .setConnectionManager(connManager)
        .build();

/* build our request */
HttpGet httpRequest = new HttpGet("https://my.host.com/page?and=stuff"); 

/* Executing our request should now hit 127.0.0.1, regardless of DNS */
HttpResponse httpResponse = httpClient.execute(httpRequest);
/*自定义DNS解析程序*/
DnsResolver DnsResolver=新系统默认DnsResolver(){
@凌驾
public InetAddress[]resolve(最终字符串主机)引发UnknownHostException{
if(host.equalsIgnoreCase(“my.host.com”)){
/*如果我们能找到我们要找的主持人,
返回我们想要的IP地址,而不是DNS中的地址*/
返回新的InetAddress[]{InetAddress.getByName(“127.0.0.1”)};
}否则{
/*否则,我们会像平常一样解决它*/
返回super.resolve(主机);
}
}
};
/*HttpClientConnectionManager允许我们使用自定义DnsResolver*/
BasicHttpClientConnectionManager connManager=新的BasicHttpClientConnectionManager(
/*我们被迫创建SocketFactory注册表。正在传递null
不强制默认注册表,所以我们重新发明了轮子*/
RegistryBuilder.create()文件
.register(“http”,PlainConnectionSocketFactory.getSocketFactory())
.register(“https”,SSLConnectionSocketFactory.getSocketFactory())
.build(),
空,/*默认连接工厂*/
null,/*默认SchemePortResolver*/
dnsResolver/*我们的dnsResolver*/
);
/*构建将使用我们的DnsResolver的HttpClient*/
HttpClient HttpClient=HttpClientBuilder.create()
.setConnectionManager(连接管理器)
.build();
/*构建我们的请求*/
HttpGet httpRequest=新的HttpGet(“https://my.host.com/page?and=stuff"); 
/*不管DNS如何,执行请求现在应该达到127.0.0.1*/
HttpResponse HttpResponse=httpClient.execute(httpRequest);

我手头没有这段代码,但您也可以编写自己的SSL处理程序/检查程序,可以进行调整或干脆忽略所有安全性。使用JDK基础网络,我们必须在内部完全忽略SSL证书进行测试。应该很容易找到示例。

当使用Apache httpClient时,有一个常见的解决方法。它使用完全不同的策略来允许这些类型的SSL连接。看一看谢谢,我知道这个解决方法,但它不应该是必要的,正如curl所做的那样。我不想信任所有证书或手动信任一个给定的证书。我只想决定将给定主机解析到哪个IP地址。我可能会使用这样的解决方法,但我想首先知道是否有更好的解决方案。根据您的情况,另一种可能是只将您想要的映射添加到/etc/hosts(或equiv)文件中。