Проблемы с функцией gethostbyname

Модератор: Модераторы разделов

Ответить
MiK13
Сообщения: 1164
ОС: Linux Debian

Проблемы с функцией gethostbyname

Сообщение MiK13 »

Есть программа. Принимает UDP пакеты от разных источников. В ней есть "фильтр" -- список IP адресов, пакеты от которых она будет обрабатывать.
Список формируется путём чтения из файла:

Код: Выделить всё

fscanf("%s",ip_s);
ip=inet_addr(ip_s);

Захотелось иметь возможность задавать IP адрес не явно, а через имя (которое определяется в /etc/hosts. Для этого решил использовать функцию gethostbyname. Для начала написал тестовую программу:

Код: Выделить всё

#include <stdio.h>
#include <netdb.h>
struct hostent *h;
int main(int argc, char **argv) {
  int i;
  h = gethostbyname(argv[1]);
  printf(" h_addr = ");
  for(i=0;i<4;i++) printf(" %d",h->h_addr[i]&255);
  putchar('\n');
  return 0;
}
Проверил -- работает:

Код: Выделить всё

$ ./th server
 h_addr =  10 20 30 1
Решил вставить этот код в программу. Вызов inet_addr(ip_s) заменил на IP_addr(ip_s) и написал функцию:

Код: Выделить всё

#include <netdb.h>
in_addr_t IP_addr(char *host) {
  char *addr;
  in_addr_t *ip;
  struct hostent *h=gethostbyname(host);
  if(!h) return h_errno;
  addr = h->h_addr;                      // Вариант А
  addr = h->h_addr_list[0];              // Вариант Б
  ip = (in_addr_t *) addr;
  return *ip;
}

Компилирую Вариант А -- выдаёт ошибку ‘struct hostent’ has no member named ‘h_addr’. Такого члена в этой структуре действительно нет, но в man gethostbyname есть запись #define h_addr h_addr_list[0] /* for backward compatibility */. И тестовый пример транслируется без ошибок. Ладно. Транслирую Вариант Б. Транслируется без ошибок. Но работает только если в файле заданы IP адреса. Имена разрешать не хочет -- gethostbyname выдаёт ошибку HOST_NOT_FOUND. Хотя тестовая программа их нормально разрешает.

В чём может быть причина?
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Проблемы с функцией gethostbyname

Сообщение NickLion »

Ищите причину в остальному коде, у меня вариант А компилируется и работает.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20752
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Проблемы с функцией gethostbyname

Сообщение Bizdelnick »

MiK13 писал(а):
25.03.2016 11:44
Имена разрешать не хочет -- gethostbyname выдаёт ошибку HOST_NOT_FOUND.

У меня Ваш код (и вариант А, ивариант Б) работает нормально. Вероятно, Вы что-то не то передаёте в качестве имени хоста.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
MiK13
Сообщения: 1164
ОС: Linux Debian

Re: Проблемы с функцией gethostbyname

Сообщение MiK13 »

NickLion писал(а):
25.03.2016 11:54
Ищите причину в остальному коде, у меня вариант А компилируется и работает.

С вариантом А, можно сказать, разобрался.
В тестовый пример добавил самую первую строку основной программы, #define _XOPEN_SOURCE 600 (без неё некоторые другие вещи не проходят), стало тоже самое:

Код: Выделить всё

$ make th
cc     th.c   -o th
th.c: In function ‘main’:
th.c:9:34: error: ‘struct hostent’ has no member named ‘h_addr’
make: *** [th] Ошибка 1
(без неё компилируется нормально)
Но тестовая программа имена разрешает.
В общем буду искать дальше


P.S.
Видимо, причина всё-таки в данной функции (IP_addr)
Вставил её код в тестовую программу, и сделал main:

Код: Выделить всё

int main(int argc, char **argv) {
  int i = IP_addr(argv[1]);
  printf(" h_addr = %08X\n",i);
  return 0;
}
Не работает. То есть явное задание IP адреса разрешает, а вот по имени не хочет.
Но меня смущает, что и системная команда host не разрешает по имени, если оно есть только в /etc/hosts. Но ей, по-моему, можно указать где искать. Но я пока не разбирался как.
Спасибо сказали:
Аватара пользователя
s.xbatob
Сообщения: 1139
ОС: Fedora

Re: Проблемы с функцией gethostbyname

Сообщение s.xbatob »

Напоминаю: gethostbyname() возвращает статические данные. Раз вы используете её в цикле, вы их должны сразу же куда-либо скопировать.
И вообще она вся - устаризм (не только поле h_addr). В новом коде лучше использовать getaddrinfo()
Спасибо сказали:
MiK13
Сообщения: 1164
ОС: Linux Debian

Re: Проблемы с функцией gethostbyname

Сообщение MiK13 »

s.xbatob писал(а):
25.03.2016 12:51
Напоминаю: gethostbyname() возвращает статические данные. Раз вы используете её в цикле, вы их должны сразу же куда-либо скопировать.
И вообще она вся - устаризм (не только поле h_addr). В новом коде лучше использовать getaddrinfo()

Я это читал. И про то, что она устарела.
Но я IP адрес извлекаю сразу после вызова. И выдаю его как значение функции.
Но, может быть, всё дело в том, что её нельзя использовать внутри функции...
Постараюсь разобраться с getaddrinfo
Спасибо сказали:
Аватара пользователя
s.xbatob
Сообщения: 1139
ОС: Fedora

Re: Проблемы с функцией gethostbyname

Сообщение s.xbatob »

MiK13 писал(а):
25.03.2016 13:04
s.xbatob писал(а):
25.03.2016 12:51
Напоминаю: gethostbyname() возвращает статические данные. Раз вы используете её в цикле, вы их должны сразу же куда-либо скопировать.
И вообще она вся - устаризм (не только поле h_addr). В новом коде лучше использовать getaddrinfo()

Я это читал. И про то, что она устарела.
Но я IP адрес извлекаю сразу после вызова. И выдаю его как значение функции.
Но, может быть, всё дело в том, что её нельзя использовать внутри функции...
Постараюсь разобраться с getaddrinfo

Вы даже структуру копируете. Только это не поможет: в ней все указатели смотрят туда же, что и в исходной.
Впрочем, вы пока только печатаете адреса, так что до этих граблей вы ещё не дошли.
Спасибо сказали:
MiK13
Сообщения: 1164
ОС: Linux Debian

Re: Проблемы с функцией gethostbyname

Сообщение MiK13 »

В общем, решил не разбираться с getaddrinfo (там, правда, есть пример из двух программ, серверной и клиентской, но каждая из них под 300 строк), а сделать сделать, как говорили марсиане, с помощью молотка, зубила и даже без "какой-то матери". И учитывая, что DNS мне не нужен (его на рабочей системе нет).

Код: Выделить всё

in_addr_t IP_addr(char *host) {
  char s[256],s_ip[20];
  in_addr_t ip=inet_addr(host);
  if(ip!=-1) return ip;
  sprintf(s,"grep -wi %s /etc/hosts",host);
  FILE *fip=popen(s,"r");
  if(!fip) return 0;
  fscanf(fip,"%s",s_ip);
  pclose(fip);
  return inet_addr(s_ip);
}
Проверил -- работает нормально.
Спасибо сказали:
Ответить