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

Curl具有手动指定要解析主机的IP的function。 例如:

curl https://google.com --resolve "google.com:443:173.194.72.113" 

这在使用HTTPS时特别有用。 如果它只是一个HTTP请求,我可以通过直接指定IP地址并添加主机头来实现相同的目的。 但是在HTTPS中会破坏连接,因为SSL证书主机将与IP地址而不是主机头进行比较。

我的问题是,我怎样才能在Java中实现同样的目标?

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

注意:仅更改HTTPS请求的主机标头不起作用。 它会抛出“javax.net.ssl.SSLPeerUnverifiedException”,强迫你信任坏证书,阻止SNI工作等等,所以真的不是一个选择。 自定义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.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); 

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