Этот вопрос почти такой же, как и ранее заданный: Получить IP-адрес локального компьютера - Вопрос. Однако мне нужно найти IP-адрес (а) Linux-машины .
Итак: Как мне - программно на C ++ - определить IP-адреса Linux-сервера, на котором работает мое приложение. У серверов будет как минимум два IP-адреса, и мне нужен конкретный (тот, который находится в данной сети (общедоступной)).
Я уверен, что для этого есть простая функция, но где?
Чтобы было немного понятнее:
- У сервера, очевидно, будет "localhost": 127.0.0.1
- Сервер будет иметь внутренний (управляющий) IP-адрес: 172.16.xx
- Сервер будет иметь внешний (публичный) IP-адрес: 80.190.xx
Мне нужно найти внешний IP-адрес, чтобы привязать к нему мое приложение. Очевидно, я также могу привязаться к INADDR_ANY (и на самом деле это то, что я делаю в данный момент). Однако я бы предпочел определять публичный адрес.
c++
linux
networking
ip-address
BlaM
источник
источник
ifconfig
иroute
т. Д. Для этойip
команды устарели . Теперь вы должны использовать это вместо этого.Ответы:
Я обнаружил, что решение ioctl проблематично для os x (которое соответствует POSIX, поэтому должно быть похоже на Linux). Однако getifaddress () позволит вам легко сделать то же самое, он отлично работает для меня на os x 10.5 и должен быть таким же, как показано ниже.
Я сделал быстрый пример ниже, который распечатает весь IPv4-адрес машины (вы также должны проверить, что getifaddrs успешно работает, т.е. возвращает 0).
Я обновил его и показывать адреса IPv6.
#include <stdio.h> #include <sys/types.h> #include <ifaddrs.h> #include <netinet/in.h> #include <string.h> #include <arpa/inet.h> int main (int argc, const char * argv[]) { struct ifaddrs * ifAddrStruct=NULL; struct ifaddrs * ifa=NULL; void * tmpAddrPtr=NULL; getifaddrs(&ifAddrStruct); for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { if (!ifa->ifa_addr) { continue; } if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4 // is a valid IP4 Address tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; char addressBuffer[INET_ADDRSTRLEN]; inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); } else if (ifa->ifa_addr->sa_family == AF_INET6) { // check it is IP6 // is a valid IP6 Address tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; char addressBuffer[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN); printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); } } if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct); return 0; }
источник
tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
lo
иwlan0
интерфейсы в моем случае. Мне нужноwlan0
илиeth0
есть подключение к Интернету. Так что, что мнеstrcmp
лучше использовать?ioctl(<socketfd>, SIOCGIFCONF, (struct ifconf)&buffer);
Читайте
/usr/include/linux/if.h
для получения информации оifconf
иifreq
структурах. Это должно дать вам IP-адрес каждого интерфейса в системе. Также прочтите/usr/include/linux/sockios.h
дополнительные ioctl.источник
Мне нравится ответ jjvainio . Как говорит Зан Линкс, он использует локальную таблицу маршрутизации, чтобы найти IP-адрес интерфейса Ethernet, который будет использоваться для подключения к определенному внешнему хосту. Используя подключенный UDP-сокет, вы можете получать информацию, фактически не отправляя никаких пакетов. Подход требует, чтобы вы выбрали конкретный внешний хост. В большинстве случаев любой хорошо известный публичный IP-адрес подойдет. Для этой цели мне нравится общедоступный адрес DNS-сервера Google 8.8.8.8, но могут быть случаи, когда вы захотите выбрать другой IP-адрес внешнего хоста. Вот код, который полностью иллюстрирует подход.
void GetPrimaryIp(char* buffer, size_t buflen) { assert(buflen >= 16); int sock = socket(AF_INET, SOCK_DGRAM, 0); assert(sock != -1); const char* kGoogleDnsIp = "8.8.8.8"; uint16_t kDnsPort = 53; struct sockaddr_in serv; memset(&serv, 0, sizeof(serv)); serv.sin_family = AF_INET; serv.sin_addr.s_addr = inet_addr(kGoogleDnsIp); serv.sin_port = htons(kDnsPort); int err = connect(sock, (const sockaddr*) &serv, sizeof(serv)); assert(err != -1); sockaddr_in name; socklen_t namelen = sizeof(name); err = getsockname(sock, (sockaddr*) &name, &namelen); assert(err != -1); const char* p = inet_ntop(AF_INET, &name.sin_addr, buffer, buflen); assert(p); close(sock); }
источник
Как вы выяснили, не существует единого «локального IP-адреса». Вот как узнать локальный адрес, который можно отправить на конкретный хост.
источник
Это имеет то преимущество, что работает со многими разновидностями unix ... и вы можете тривиально изменить его для работы с любыми o / s. Все приведенные выше решения дают мне ошибки компилятора в зависимости от фазы луны. В тот момент, когда есть хороший способ POSIX для этого ... не используйте его (в то время, когда это было написано, это было не так).
// ifconfig | perl -ne 'print "$1\n" if /inet addr:([\d.]+)/' #include <stdlib.h> int main() { setenv("LANG","C",1); FILE * fp = popen("ifconfig", "r"); if (fp) { char *p=NULL, *e; size_t n; while ((getline(&p, &n, fp) > 0) && p) { if (p = strstr(p, "inet ")) { p+=5; if (p = strchr(p, ':')) { ++p; if (e = strchr(p, ' ')) { *e='\0'; printf("%s\n", p); } } } } } pclose(fp); return 0; }
источник
ifconfig
. Вы должны использоватьip
сейчас. Правильный способ генерации языка нейтральный вывод является заданнойLANG
переменной окруженияC
, как:LANG=C ls -l
Я не думаю, что есть однозначный правильный ответ на ваш вопрос. Вместо этого существует множество способов приблизиться к желаемому. Поэтому я дам несколько советов, как это сделать.
Если на машине более 2 интерфейсов (
lo
считается за один), у вас возникнут проблемы с автоматическим определением нужного интерфейса. Вот несколько рецептов, как это сделать.Проблема, например, в том, что хосты находятся в DMZ за брандмауэром NAT, который меняет общедоступный IP-адрес на какой-то частный и пересылает запросы. У вашей машины может быть 10 интерфейсов, но только один соответствует общедоступному.
Даже автоматическое определение не работает, если вы используете двойной NAT, когда ваш брандмауэр даже переводит исходный IP-адрес во что-то совершенно другое. Таким образом, вы даже не можете быть уверены, что маршрут по умолчанию ведет к вашему интерфейсу с общедоступным интерфейсом.
Обнаружить его по маршруту по умолчанию
Что-то вроде
ip r get 1.1.1.1
обычно сообщает вам интерфейс, у которого есть маршрут по умолчанию.Если вы хотите воссоздать это на своем любимом языке сценариев / программирования, используйте
strace ip r get 1.1.1.1
и следуйте по дороге из желтого кирпича.Установите его с помощью
/etc/hosts
Вы можете создать запись
/etc/hosts
как80.190.1.3 publicinterfaceip
Затем вы можете использовать этот псевдоним
publicinterfaceip
для ссылки на свой общедоступный интерфейс.Используйте окружающую среду
То же, что и
/etc/hosts
. но используйте для этого среду. Вы можете попробовать/etc/profile
или~/.profile
для этого.Следовательно, если вашей программе нужна переменная,
MYPUBLICIP
вы можете включить такой код (это C, не стесняйтесь создавать C ++ из него):#define MYPUBLICIPENVVAR "MYPUBLICIP" const char *mypublicip = getenv(MYPUBLICIPENVVAR); if (!mypublicip) { fprintf(stderr, "please set environment variable %s\n", MYPUBLICIPENVVAR); exit(3); }
Итак, вы можете назвать свой скрипт / программу
/path/to/your/script
следующим образомMYPUBLICIP=80.190.1.3 /path/to/your/script
это работает даже в
crontab
.Перечислите все интерфейсы и удалите те, которые вам не нужны
Если вы знаете, чего не хотите, вы можете перечислить все интерфейсы и игнорировать все ложные.
Кажется, здесь уже есть ответ https://stackoverflow.com/a/265978/490291 для этого подхода.
Сделайте это как DLNA
Вы можете попробовать перечислить все шлюзы UPnP в вашей сети и таким образом найти правильный маршрут для какой-то «внешней» вещи. Это может быть даже на маршруте, на который не указывает ваш маршрут по умолчанию.
Подробнее об этом, возможно, см. Https://en.wikipedia.org/wiki/Internet_Gateway_Device_Protocol.
Это дает вам хорошее представление о том, какой из них является вашим настоящим общедоступным интерфейсом, даже если ваш маршрут по умолчанию указывает в другом месте.
Есть даже больше
Маршрутизаторы IPv6 рекламируют себя, чтобы дать вам правильный префикс IPv6. Глядя на префикс, вы подскажете, какой у него внутренний IP-адрес или глобальный.
Вы можете прослушивать кадры IGMP или IBGP, чтобы найти подходящий шлюз.
Имеется менее 2 ^ 32 IP-адресов. Следовательно, в локальной сети не требуется много времени, чтобы просто пропинговать их все. Это дает вам статистическую информацию о том, где с вашей точки зрения расположена большая часть Интернета. Однако вы должны быть немного разумнее, чем знаменитый https://de.wikipedia.org/wiki/SQL_Slammer
ICMP и даже ARP - хорошие источники информации о боковой полосе сети. Это также может помочь вам.
Вы можете использовать широковещательный адрес Ethernet для связи со всеми устройствами сетевой инфраструктуры, которые часто помогают, например, DHCP (даже DHCPv6) и так далее.
Этот дополнительный список, вероятно, бесконечен и всегда неполон, потому что каждый производитель сетевых устройств усердно изобретает новые дыры в безопасности, чтобы автоматически определять свои собственные устройства. Что часто очень помогает в том, как обнаружить публичный интерфейс там, где его не должно быть.
'Достаточно. Вне.
источник
В дополнение к тому, что сказал Стив Бейкер, вы можете найти описание SIOCGIFCONF ioctl на странице руководства netdevice (7) .
Когда у вас есть список всех IP-адресов на хосте, вам придется использовать логику приложения, чтобы отфильтровать нежелательные адреса и надеяться, что у вас остался один IP-адрес.
источник
Не программируйте жестко: это то, что может измениться. Многие программы выясняют, к чему привязываться, читая файл конфигурации и делая все, что в нем говорится. Таким образом, если вашей программе когда-нибудь в будущем потребуется привязка к чему-то, что не является общедоступным IP-адресом, она сможет это сделать.
источник
Поскольку в вопросе указывается Linux, мой любимый метод определения IP-адресов машины - это использование netlink. Создав сокет netlink протокола NETLINK_ROUTE и отправив RTM_GETADDR, ваше приложение получит сообщение (я), содержащее все доступные IP-адреса. Примером может служить здесь .
Для упрощения обработки сообщений используется libmnl. Если вам интересно узнать больше о различных параметрах NETLINK_ROUTE (и о том, как они анализируются), лучшим источником является исходный код iproute2 (особенно приложение монитора), а также функции приема в ядре. Страница руководства rtnetlink также содержит полезную информацию.
источник
Вы можете сделать некоторую интеграцию с curl очень просто:
curl www.whatismyip.org
из оболочки вы получите ваш глобальный IP-адрес. Вы вроде как полагаетесь на какой-то внешний сервер, но всегда будете им, если находитесь за NAT.источник
Элегантное скриптовое решение для Linux можно найти по адресу: http://www.damnsmalllinux.org/f/topic-3-23-17031-0.html
источник
// Use a HTTP request to a well known server that echo's back the public IP address void GetPublicIP(CString & csIP) { // Initialize COM bool bInit = false; if (SUCCEEDED(CoInitialize(NULL))) { // COM was initialized bInit = true;
// Create a HTTP request object MSXML2::IXMLHTTPRequestPtr HTTPRequest; HRESULT hr = HTTPRequest.CreateInstance("MSXML2.XMLHTTP"); if (SUCCEEDED(hr)) { // Build a request to a web site that returns the public IP address VARIANT Async; Async.vt = VT_BOOL; Async.boolVal = VARIANT_FALSE; CComBSTR ccbRequest = L"http://whatismyipaddress.com/"; // Open the request if (SUCCEEDED(HTTPRequest->raw_open(L"GET",ccbRequest,Async))) { // Send the request if (SUCCEEDED(HTTPRequest->raw_send())) { // Get the response CString csRequest = HTTPRequest->GetresponseText(); // Parse the IP address CString csMarker = "<!-- contact us before using a script to get your IP address -->"; int iPos = csRequest.Find(csMarker); if (iPos == -1) return; iPos += csMarker.GetLength(); int iPos2 = csRequest.Find(csMarker,iPos); if (iPos2 == -1) return; // Build the IP address int nCount = iPos2 - iPos; csIP = csRequest.Mid(iPos,nCount); } } } } // Unitialize COM if (bInit) CoUninitialize();
}
источник