title: Override DNS For Specific Domains Like A Hosts File, But Without Using Hosts file
body: <p>I need to issue a series of parallelized web requests from the same server to a specific domain, but control what IP address these requests actually go to.  Originally, I came up with a scheme where I would request the IP I wanted specifically, and then manually set the <code>Host: www.example.com</code> header on the request, and use a series of handlers to make sure that redirects issued followed the same pattern.</p>
  
  <p>This seemed to work for some time, but lately I've been having trouble with redirects to HTTPS.  The handshake will fail, and the request in turn.  <s>I have tried disabling SSL verification in a variety of ways, including:</p>
  
  <pre><code>local $ENV{ PERL_LWP_SSL_VERIFY_HOSTNAME } = 0;
  local $ENV{ HTTPS_DEBUG }                  = 1;
  
  $ua-&gt;ssl_opts(
      SSL_ca_file =&gt; Mozilla::CA::SSL_ca_file(),
      verify_hostname =&gt; 0,
      SSL_verify_mode =&gt; 0x00,
  );
  
  IO::Socket::SSL::set_ctx_defaults(
      SSL_verifycn_scheme =&gt; 'www',
      SSL_verify_mode =&gt; 0,
  );        
  </code></pre>
  
  <p></s>
  I have also tried using <a href="http://search.cpan.org/~masaki/LWP-UserAgent-DNS-Hosts-0.05/README.pod" rel="nofollow noreferrer">LWP::UserAgent::DNS::Hosts</a> to solve the problem, but it persists.</p>
  
  <p><strong>&lt;edit>I should note that the reason why turning off peer validation for SSL is not solving the problem is likely because for some reason requesting this way is actually causing the handshake to fail, not failing on a validation point.&lt;/edit></strong></p>
  
  <p>One thing that works is making an entry in <code>/etc/hosts</code> to point the domain at the appropriate IP, however this is not practical, because I may need to run tens, or hundreds, of tests, in parallel, on the same domain.</p>
  
  <p>Is there a way to emulate the functionality of adding an entry to <code>/etc/hosts</code> that does not involve requesting the IP specifically and overriding the <code>Host: ...</code> HTTP header?</p>
  
  <h3>EDIT: SSL Debug Info</h3>
  
  <pre><code>DEBUG: .../IO/Socket/SSL.pm:1914: new ctx 140288835318480
  DEBUG: .../IO/Socket/SSL.pm:402: socket not yet connected
  DEBUG: .../IO/Socket/SSL.pm:404: socket connected
  DEBUG: .../IO/Socket/SSL.pm:422: ssl handshake not started
  DEBUG: .../IO/Socket/SSL.pm:455: not using SNI because hostname is unknown
  DEBUG: .../IO/Socket/SSL.pm:478: set socket to non-blocking to enforce timeout=180
  DEBUG: .../IO/Socket/SSL.pm:491: Net::SSLeay::connect -&gt; -1
  DEBUG: .../IO/Socket/SSL.pm:501: ssl handshake in progress
  DEBUG: .../IO/Socket/SSL.pm:511: waiting for fd to become ready: SSL wants a read first
  DEBUG: .../IO/Socket/SSL.pm:531: socket ready, retrying connect
  DEBUG: .../IO/Socket/SSL.pm:491: Net::SSLeay::connect -&gt; -1
  DEBUG: .../IO/Socket/SSL.pm:1388: SSL connect attempt failed with unknown error
  
  DEBUG: .../IO/Socket/SSL.pm:497: fatal SSL error: SSL connect attempt failed with unknown error error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
  DEBUG: .../IO/Socket/SSL.pm:1948: free ctx 140288835318480 open=140288835318480
  DEBUG: .../IO/Socket/SSL.pm:1953: free ctx 140288835318480 callback
  DEBUG: .../IO/Socket/SSL.pm:1956: OK free ctx 140288835318480
  </code></pre>
  
  <p>And in the response I get:</p>
  
  <blockquote>
    <p>Can't connect to redacted.org:443</p>
    
    <p><code>SSL connect attempt failed with unknown error error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure at /System/Library/Perl/Extras/5.18/LWP/Protocol/http.pm line 51.</code></p>
  </blockquote>
  
  <p>It fails equally well on our server (using an older legacy version of Perl, which I will not disclose here as it seems irrelevant).</p>
  
  <p>The server initially responds to a non-HTTPS request with a 301 redirect to the HTTPS site.  Then the failure occurs.  I will post reproducing code with the specific details of my request removed, but any site which redirects non-HTTPS traffic to HTTPS should suffice.</p>
  
  <pre><code>use IO::Socket::SSL qw/ debug4 /;
  use LWP::UserAgent;
  use LWP::UserAgent::DNS::Hosts;
  use HTTP::Request;
  use Mozilla::CA;
  use Data::Dumper;
  
  LWP::UserAgent::DNS::Hosts-&gt;register_hosts(
      'recacted.org' =&gt; '127.0.0.1', # no I am not redirecting to loopback in reality, this is anonymized
      'www.redacted.org' =&gt; '127.0.0.1',
  );
  
  LWP::UserAgent::DNS::Hosts-&gt;enable_override;
  
  my $ua = LWP::UserAgent-&gt;new;
  $ua-&gt;ssl_opts( SSL_ca_file =&gt; Mozilla::CA::SSL_ca_file() );
  
  my $request = HTTP::Request-&gt;new(GET =&gt; 'http://redacted.org/');
  
  my $response = $ua-&gt;request($request);
  
  print $response-&gt;content; #Dumper ( $response-&gt;is_success ? $response-&gt;headers : $response );
  </code></pre>
  
  <p>Again, that is not the production code, just enough code to reproduce the issue.  It doesn't seem to have anything to do with SSL verification, but moreover an inability to negotiate the request, presumably because <code>LWP::UserAgent::DNS::Hosts</code> is doing exactly what I was doing: changing the request target to the desired IP, and then writing the <code>Host: ...</code> header manually.  Why this causes the SSL handshake to fail, I do not know.</p>
  
  <p>On my local machine debugging</p>
  
  <pre><code>openssl version -a: 1.0.2j 26 Sep 2016
  IO::Socket::SSL-&gt;VERSION == 1.966
  Net::SSLeay-&gt;VERSION == 1.72
  </code></pre>
  
  <p>On a server of ours</p>
  
  <pre><code>openssl version -a: 1.0.1t 3 May 2016
  IO::Socket::SSL-&gt;VERSION == 1.76
  Net::SSLeay-&gt;VERSION == 1.48
  </code></pre>