How to override DNS in HTTP connections in Java

前端 未结 2 1733
隐瞒了意图╮
隐瞒了意图╮ 2020-12-03 06:15

Curl has a feature for manually specifying which IP to resolve a host to. For example:

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


        
相关标签:
2条回答
  • 2020-12-03 06:35

    If using Apache's HttpClient, you can create a custom DNS resolver to detect the host you'd like to redirect, and then provide a substitute IP address.

    Note: Just changing the Host header for HTTPS requests doesn't work. It will throw "javax.net.ssl.SSLPeerUnverifiedException", forcing you to trust bad certificates, stop SNI from working, etc., so really not an option. A custom DnsResolver is the only clean way I've found to get these requests to work with HTTPS in Java.

    Example:

    /* 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);
    
    0 讨论(0)
  • 2020-12-03 06:47

    I don't have the code close at hand, but you can also write your own SSL handler/checker that could adapt or flat-out just ignore all the security. Using the JDK base networking, we had to totally ignore SSL certificates internally for testing. Should be easy to find examples.

    0 讨论(0)
提交回复
热议问题