Skip to content
Advertisement

PHP cURL: could not resolve host (over VPN)

I work remotely and can access internal servers via VPN. When my VPN connection is established, I can reach my webserver via curl:

curl http://sub.mydomain.com

I can also reach the webserver in a browser by going to http://sub.mydomain.com. So this does not seem to be a DNS issue with the webserver itself.

When developing my Laravel 4.2 application (PHP 5.6) served locally via Apache, however, php’s curl_exec fails to resolve the host. Oddly, php’s gethostbyname($hostname) correctly resolves the host. I have tried forcing IPv4 as I have read IPv6 can result in failures of this type with no success.

// works
$ip = gethostbyname($hostname);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://$ip/path");
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_exec($ch);

// does NOT work
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://$hostname/path");
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_exec($ch);

This leaves me at a loss. I don’t understand how PHP curl handles DNS resolution (clearly not with gethostbyname). I also don’t understand exactly how DNS lookups on private networks work in the first place. So I really don’t know where to look to get PHP curl to resolve my private hosts.

Advertisement

Answer

Command line curl resolved the host. Browser resolved the host. Only PHP curl failed to resolve it.

Ultimately, the issue came down to the curl configuration. I installed PHP with homebrew and as a dependency it installed curl-openssl to be used by PHP. This install of curl is configured by the brew formula to use c-ares for domain name resolution. I don’t know how c-ares works, but this VPN DNS is apparently an edge case it does not handle correctly on OS X (perhaps due to OS X doing a lousy job of keeping /etc/resolv.conf up to date).

/usr/bin/curl on the other hand was configured to use the native OS X resolver. This is the same resolver used by PHP’s gethostbyname and the web browser, which explains why both of those work as expected.

$ brew uninstall --ignore-dependencies curl-openssl

This resolved my issue by dumping this “broken” curl installation. I am not sure how the fallback mechanism works, but I believe PHP is now using /usr/bin/curl since I have no other installations of curl (that I know about) and the curl version listed in phpinfo() now matches /usr/bin/curl when before it did not.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement