152

Let's say a website is load-balanced between several servers. I want to run a command to test whether it's working, such as curl DOMAIN.TLD. So, to isolate each IP address, I specify the IP manually. But many websites may be hosted on the server, so I still provide a host header, like this: curl IP_ADDRESS -H 'Host: DOMAIN.TLD'. In my understanding, these two commands create the exact same HTTP request. The only difference is that in the latter one I take out the DNS lookup part from cURL and do this manually (please correct me if I'm wrong).

All well so far. But now I want to do the same for an HTTPS url. Again, I could test it like this curl https://DOMAIN.TLD. But I want to specify the IP manually, so I run curl https://IP_ADDRESS -H 'Host: DOMAIN.TLD'. Now I get a cURL error:

curl: (51) SSL: certificate subject name 'DOMAIN.TLD' does not match target host name 'IP_ADDRESS'.

I can of course get around this by telling cURL not to care about the certificate (the "-k" option) but it's not ideal.

Is there a way to isolate the IP address being connected to from the host being certified by SSL?

Ladadadada
  • 27,207
Martin
  • 4,275

4 Answers4

227

Think I found a solution going through the cURL manual:

curl https://DOMAIN.EXAMPLE --resolve 'DOMAIN.EXAMPLE:443:192.0.2.17'

Added in [curl] 7.21.3. Removal support added in 7.42.0.

from CURLOPT_RESOLVE explained

Paul
  • 3,278
Martin
  • 4,275
32

Here is the man entry for the currently most upvoted answer since they only included a link to the programmatic component:

--resolve <host:port:address>
Provide  a  custom  address  for  a specific host and port pair. Using
this, you can make the curl requests(s) use a specified address and 
prevent the otherwise normally resolved address to be used. Consider 
it a sort of /etc/hosts alternative provided on the command line. 
The port number should be the number used for the specific protocol 
the host will be used for. It means you need several entries if you 
want to provide address for the same host but different ports.

The provided address set by this option will be used even if -4, 
--ipv4 or -6, --ipv6 is set to make curl use another IP version.

This option can be used many times to add many host names to resolve.

Added in 7.21.3.

But due to the limitation given ("It means you need several entries if you want to provide address for the same host but different ports."), I would consider another, newer option that can translate both at the same time:

--connect-to <HOST1:PORT1:HOST2:PORT2>
For  a request to the given HOST:PORT pair, connect to 
CONNECT-TO-HOST:CONNECT-TO-PORT instead. This option is suitable 
to direct requests at a specific server, e.g. at a specific cluster 
node in a cluster of servers. This option is only used to establish 
the network connection. It does NOT affect the hostname/port that 
is used for TLS/SSL (e.g. SNI, certificate verification) or for 
the application protocols. &quot;host&quot; and &quot;port&quot; may be the empty string, 
meaning &quot;any host/port&quot;. &quot;connect-to-host&quot; and &quot;connect-to-port&quot; 
may also be the empty string, meaning &quot;use the request's original host/port&quot;.

This option can be used many times to add many connect rules.

See also --resolve and -H, --header. 
Added in 7.49.0.

Example using --connect-to:

curl https://domain.example --connect-to domain.example:443:203.0.113.81:443
Paul
  • 3,278
peedee
  • 531
  • 6
  • 12
16

You can change in /etc/hosts to make the server think that the domain is located at a certain IP.

This is the syntax:

192.168.10.20 www.domain.tld

This will make cURL use the IP-address you want without the SSL-certificate to break.

miono
  • 566
6

If you're running curl in Windows, use double quotes

curl https://DOMAIN.TLD --resolve "DOMAIN.TLD:443:IP_ADDRESS"

curl DOMAIN.TLD --resolve "DOMAIN.TLD:80:IP_ADDRESS"

You can skip the scheme/protocol up front, but you can't skip the port number in the --resolve string.