Как получить мой IP-адрес без обратной связи в C? - PullRequest
3 голосов
/ 09 марта 2009

Для связи между двумя хостами мне нужно отправить IP-адрес моего хоста на другой сайт. Проблема заключается в том, что, если я запрашиваю свой IP-адрес, возможно, я получаю обратно свои локальные петлевые IP-адреса (127.x.x.x), а не сетевой (ethernet) IP-адрес.

Я использую следующий код:

char myhostname[32];


gethostname(myhostname, 32);
hp = gethostbyname(myhostname);
unsigned my_ip = *(unsigned*)(hp->h_addr);

if( (my_ip % 256) == 127) {
  /* Wrong IP adress as it's 127.x.x.x */
  printf("Error, local IP address!");
  return;
}

Единственный способ решить эту проблему - убедиться, что мое имя хоста в / etc / hosts находится за реальным сетевым адресом, а не за локальной петлей (по умолчанию, например, в Ubuntu).

Есть ли способ решить эту проблему, не полагаясь на содержимое / etc / hosts?

Редактировать: Я изменил вышеуказанный код, чтобы он использовал getaddrinfo, но я все равно получаю номер устройства обратной связи (127.0,0,1) вместо реального IP-адреса:

struct addrinfo hint = {0};
struct addrinfo *aip = NULL;
unsigned ip = 0;
struct sockaddr_in *sinp = NULL;

hint.ai_family = AF_INET; /* IPv4 */
hint.ai_socktype = SOCK_STREAM;

if(getaddrinfo(hostname, NULL, &hint, &aip) != 0) {
    return 0;
}
sinp = (struct sockaddr_in *) aip->ai_addr;
ip   = *(unsigned *) &sinp->sin_addr;

(Раньше я получал список из 3-х аддринфо с тремя SOCK_STREAM, SOCK_DGRAM и SOCK_RAW, но подсказка предотвращает это)

Так что мой вопрос все еще стоит ...

Ответы [ 10 ]

9 голосов
/ 09 марта 2009

Существует функция POSIX getaddrinfo(), которая возвращает связанный список адресов для данного имени хоста, поэтому вам просто нужно пройти по этому списку и найти адрес без обратной связи.

См. man getaddrinfo.

4 голосов
/ 09 марта 2009

Адрес отправителя будет включен в отправленный пакет ... нет необходимости дублировать эту информацию. Он получается при принятии сообщения от удаленного хоста (см. Руководство beej по работе с сетями, в частности, часть по accept () )

4 голосов
/ 09 марта 2009

Не ответ, а соответствующий комментарий: имейте в виду, что как только вы начинаете отправлять адресную информацию в содержимом пакетов, вы рискуете сделать ваше приложение неспособным работать через NAT: ing маршрутизаторы и / или через брандмауэры.

Эти технологии полагаются на информацию в заголовках IP-пакетов для отслеживания трафика, и если приложения обмениваются адресной информацией внутри пакетов, где они остаются невидимыми для этой проверки, они могут сломаться.

Конечно, это может быть совершенно неуместно для вашего приложения, но я подумал, что стоит указать в этом контексте.

3 голосов
/ 09 января 2010

Я просто столкнулся с ситуацией, когда информация содержится только в / etc / hosts и когда я использовал getaddrinfo для получения списка IP-адресов, он каждый раз возвращал 127.0.0.1. Как оказалось, имя хоста было псевдонимом localhost ... что-то, что часто легко пропустить. Вот что случилось:

Файл / etc / hosts:
127.0.0.1 localhost.localdomain localhost foo
:: 1 localhost6.localdomain6 localhost6
172.16.1.248 foo
172.16.1.249 Би
172.16.1.250 bletch

Итак, теперь, когда вы вызываете getaddrinfo с host = "foo", он возвращает 127.0.0.1 3 раза. Ошибка здесь в том, что foo появляется как на строке с «127.0.0.1», так и «172.16.1.248». Как только я удалил foo из строки "127.0.0.1", все заработало нормально.

Надеюсь, это кому-нибудь поможет.

1 голос
/ 09 марта 2009

Посмотрите на это: Программное обнаружение публичного IP

Обратите внимание, что в некоторых случаях у компьютера может быть несколько IP-адресов без обратной связи, и в этом случае ответы на этот вопрос говорят о том, как получить тот, который доступен в Интернете.

0 голосов
/ 01 апреля 2009

Ваш новый код использует IPv4 (в поле hint.ai_family), что является ужасной идеей.

Кроме того, вы близки, вам просто нужно просмотреть результаты getaddrinfo. Ваш код только получает первый IP-адрес, но есть поле aip-> ai_next, которое следует за ...

struct addrinfo {
       ...
       struct addrinfo *ai_next;       /* next structure in linked list */
};
0 голосов
/ 31 марта 2009

Если / etc / hosts все еще там и все тот же, поиск всех записей в h_addr_list не поможет.

0 голосов
/ 09 марта 2009

Ты почти у цели. Я не уверен, как вы получаете my_ip от hp.

gethostbyname() возвращает указатель на структуру hostent, которая имеет поле h_addr_list.

Поле h_addr_list представляет собой список с нулевым символом в конце всех IP-адресов, привязанных к этому хосту.

Я думаю, что вы получаете адрес обратной связи, потому что это первая запись в h_addr_list.

РЕДАКТИРОВАТЬ: он должен работать примерно так:

gethostname(myhostname, 32);
hp = gethostbyname(myhostname);
unsigned my_ip = *(unsigned*)(hp->h_addr);

for (int i = 0; hp->h_addr_list[i] != 0; ++i) {
  if (hp->h_addr_list[i] != INADDR_LOOPBACK) {
    // hp->addr_list[i] is a non-loopback address
  }
}
// no address found
0 голосов
/ 09 марта 2009

Использование getaddrinfo()

0 голосов
/ 09 марта 2009

Даже если компьютер имеет только один физический сетевой интерфейс (предположение, которое может или не может быть, даже у нетбуков есть два - Ethernet и WLAN), VPN может добавить еще больше IP-адресов. В любом случае, хост с другой стороны должен быть в состоянии определить IP-адрес вашего хоста, с которым он связался.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...