libcurl - прямое соединение с IP
Подскажите пожалуйста, вот пытаюсь сделать запрос на сервер с libcurl не через доменное - ru.stackoverflow.com, а через указание прямого IP-шника: 151.101.65.69
В принципе беру чисто пример из документации и подставляю туда свои данные для ru.stackoverflow.com:
struct curl_slist* host = NULL;
host = curl_slist_append(NULL, "mysite.com:777:151.101.65.69"); //IP - ru.stackoverflow.com
curl_easy_setopt(CURL_p, CURLOPT_RESOLVE, host);
curl_easy_setopt(CURL_p, CURLOPT_URL, "mysite.com");
Однако - CURLOPT_RESOLVE - или работает некорректно или я не правильно понял, как оно должно работать.
Я предполагал, что опция CURLOPT_RESOLVE - должна, как бы виртуально создать "запись в DNS" о указанном Хосте и соответствующим указном IP-адресе.
И когда, я вызываю уже CURLOPT_URL, то URL указанный, как "mysite.com" будет искаться среди "виртуального DNS", однако - этого не происходит и идет реальный resolve URL через DNS и подключение к IP-адресу именно mysite.com.
PS:Разобрался, для меня не сразу было очевидно:
CURLOPT_RESOLVE - создает некий "виртуальный либкуровский кеш DNS", с помощью curl_slist_append я добавляю туда запись к примеру"mysite.com:777:151.101.65.69".
Далее я взываю CURLOPT_URL, после чего данный указанный URL сначала ищется в этом "виртуальном DNS`е", если находится соответствие, то запрос идет именно на "mysite.com:777:151.101.65.69", если не находится, то делается реальный запрос к реальному DNS.
Но тут оказался нюанс, который подсказал Kotomi и который я не сразу понял: если я в CURLOPT_URL - указал "mysite.com", то это означает, mysite.com:80, если бы указал https:\\mysite.com, то означало бы естественно mysite.com:443, в итоге получилось, что при вызове CURLOPT_URL - запись mysite:80.com искалась среди "виртуального DNS" среди записи mysite.com:777 и в итоге соответствие не находилось, и libcurl делал реальный запрос к DNS на ресолв mysite.com, и оказалось, что такой сайт действительно есть, и DNS возвращало реальный IP-шник и соответвенно страницу я получал именно этого сайта.
Ответы (1 шт):
Когда то в далекие-далекие времена на одном сервере был один сайт. И если обратится по айпи, то сервер с легкостью мог отдать содержимое этого сайта. Но пришли другие времена и иногда одному сайту нужно десяток серверов, а иногда на одном сервере может лежать (лежать:) ) десяток сайтов. И вот в этом втором случае возникает вопрос, а как серверу узнать, какой именно сайт хочет клиент. Ведь домен был преобразован в айпи и к нему уже пришли с айпи.
Умные дядьки подумали и решили добавить прям в заголовки доменное имя, добавив для этого заголовок Host. Сервер (то есть apache/nginx или подобное) теперь мог заглянуть внутрь (а он это и так делает обычно, для разных целей), посмотреть желаемый хост и перенаправить/поправить запрос. Все, проблема решена.
Некоторые сайты (такие как stackoverflow) пошли ещё дальше, они одновременно на нескольких серверах и несколько доменов. Это достаточно удобно.
Вернемся к нашим баранам. Как же сделать запрос по айпи и при этом получить страницу. Вот Вам минимальный пример с моими комментариями.
#include <curl/curl.h>
int main(int argc, char *argv[])
{
CURLcode ret;
CURL *hnd;
struct curl_slist *slist1;
slist1 = NULL;
// вот оно, самое важное!!!
slist1 = curl_slist_append(slist1, "Host: ru.stackoverflow.com");
// инициализируем по классике
hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
curl_easy_setopt(hnd, CURLOPT_URL, "https://151.101.65.69/");
curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
// добавим наш хедер
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, slist1);
curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.74.0");
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
// у меня не хотело, просило сертификаты
curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L);
// весь код взят с другого примера, возможно тут есть лишнее
curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
ret = curl_easy_perform(hnd);
curl_easy_cleanup(hnd);
hnd = NULL;
curl_slist_free_all(slist1);
slist1 = NULL;
return (int)ret;
}
Если же хочется использовать CUROLOPT_RESOLVE, то можно просто серединку поменять на такое
slist1 = NULL;
slist1 = curl_slist_append(slist1, "ru.stackoverflow.com:443:151.101.65.69:443");
hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
curl_easy_setopt(hnd, CURLOPT_URL, "https://ru.stackoverflow.com/");