简体   繁体   中英

java: make Apache HttpClient connect to host with specific IP

Some domain names are resolved to several IPs by DNS. I need to make http requests to all those IPs (a kind of service healthcheck). I can use

InetAddress[] addrs = InetAddress.getAllByName("google.com")

to resolve all IPs which should be checked. It is not about google, but it is with testing on google that I've found puzzles

I'm trying to use Apache HttpClient to make request. Like this:

HttpHead req = new HttpHead(url);
//InetAddress addr = InetAddress.getByAddress("google.com", new byte[] {74, 125, (byte) 131, 101});
InetAddress addr = // one of those we got from InetAddress.getAll...
CloseableHttpResponse resp = cli.execute(new HttpHost(addr, 443, "https"), req);

It seems to work, however I decided to check it constructing the IP manually - see the commented string. If it is uncommented and used instead of the addr from the dns enumeration, all works fine, returning 200.

But if I then change IP address to 8, 8, 8, 8 in this line and expect to get connection timeout (as it is address of google's dns which don't listen on 443 port, it is firewalled) - I see 404 instead. Thus I am not sure it uses the specified IP for real connection rather than for verification.

This makes me think that the approach is wrong and I use this HttpHost incorrectly.

Alternative approach is to use custom DnsResolver set up for given HttpClient , which will feed only specific IPs, and do it in turns. however this looks like ugly and inconvenient hack so I'm searching for "proper" way...

PS variant with sending requests in plain text to sockets (without any library) will work fine, but most probably solution will need to work with https also which makes this variant difficult.

Your approach to hit a specific IP is correct and works:

try {
    HttpClient hc = HttpClientBuilder.create().build();
    HttpGet req = new HttpGet("https://www.google.com");
    HttpResponse res = hc.execute(new HttpHost("8.8.8.8", 443, "https"), req);
    System.out.println(res.getStatusLine());
} catch (Exception e) {
    System.out.println(e.getMessage());
}

Prints:

Certificate for <8.8.8.8> doesn't match any of the subject alternative names: [*.c.docs.google.com, .....

Apparently the Google's Public DNS server 8.8.8.8 in addition to DNS also listens on port 443:

$ openssl s_client -showcerts -connect 8.8.8.8:443 | more
CONNECTED(0000012C)
---
Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google LLC/CN=*.c.docs.google.com
   i:/C=US/O=Google Trust Services/CN=Google Internet Authority G3

Now I can't speak intelligently about the content it is serving, but I can conclude that 8.8.8.8 isn't meant to handle https://www.google.com traffic since neither *.c.docs.google.com nor any of the subject alternative names match www.google.com .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM