Трассировка хмелей ttl reciveform на ios

Я пытаюсь реализовать простой traceroute для iOS. Кажется, все работает нормально, за исключением того, что когда-то, когда я запускаю свое приложение на симуляторе или на устройстве, оно находит только несколько (6-7) первых маршрутизаторов на пути, когда трассировка CLI находит все 14 маршрутизаторов.

const char *c = "www.gmail.com";
struct hostent *host_entry = gethostbyname(c);
char *ip_addr;
ip_addr = inet_ntoa(*((struct in_addr *)host_entry->h_addr_list[0]));
struct sockaddr_in destination, fromAddr;
int recv_sock;
int send_sock;

// Creting Sockets///

if ((recv_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP)) <
    0) // using UDP socket.
{
  NSLog(@"Could not cretae recv_sock.\n");
}
if ((send_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  NSLog(@"Could not cretae send_sock.\n");
}
memset(&destination, 0, sizeof(destination));
destination.sin_family = AF_INET;
destination.sin_addr.s_addr = inet_addr(ip_addr);
destination.sin_port = htons(80);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 10000;
setsockopt(recv_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
           sizeof(struct timeval));
char *cmsg = "GET / HTTP/1.1\r\n\r\n";
int max_ttl = 20;
int num_attempts = 5;
socklen_t n = sizeof(fromAddr);
char buf[100];
for (int ttl = 1; ttl <= max_ttl; ttl++) {
  memset(&fromAddr, 0, sizeof(fromAddr));
  if (setsockopt(send_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0)
    NSLog(@"error in setsockopt\n");
  for (int try = 0; try < num_attempts; try ++) {
    if (sendto(send_sock, cmsg, sizeof(cmsg), 0,
               (struct sockaddr *)&destination,
               sizeof(destination)) != sizeof(cmsg))
      NSLog(@"error in send to...\n@");
    int res = 0;
    if ((res = recvfrom(recv_sock, buf, 100, 0, (struct sockaddr *)&fromAddr,
                        &n)) < 0) {
      NSLog(@"an error: %s; recvfrom returned %d\n", strerror(errno), res);
    } else {
      char display[16] = {0};
      inet_ntop(AF_INET, &fromAddr.sin_addr.s_addr, display, sizeof(display));
      NSLog(@"Received packet from%s for TTL=%d\n", display, ttl);
      break;
    }
  }
}

Я пытался связать сокет отправки, но у меня те же результаты, и я не могу использовать Sock_raw на iOS. Я попытался запустить его на моем Mac и получил те же результаты. Я получаю ошибку "Ресурс временно недоступен"; для recvfrom(), Это почему? Как я могу это исправить?

1 ответ

Решение

EAGAIN ошибка (производящая строку "Ресурс временно недоступен;") может быть вызвана таймаутом принимающего сокета.

Так как вы устанавливаете только 10000 микросекунд как тайм-аут чтения (это действительно короткое ИМХО) с этой строкой...

struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 10000;
setsockopt(recv_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));

... возможно, что чем длиннее путь (я имею в виду количество маршрутизаторов, через которые вы должны пройти), тем больше у вас шансов в этой ситуации.

Попробуйте увеличить значение тайм-аута и дайте нам знать, если он стал лучше.

РЕДАКТИРОВАТЬ

Я попробовал исходный код под Linux, и я заметил два вида проблем.

  • Как уже упоминалось выше: тайм-ауты
  • Проблема с портом 80

Я просто увеличил время ожидания и использовал порт, отличный от 80 (в моем случае я отправил сообщение udp на порт 40000), и я получил все прыжки, как traceroute команда.

Я не уверен, почему такое поведение происходит. Может быть, какой-то "возможный вредоносный пакетный сигнал тревоги" запускается маршрутизатором, который его отбрасывает

ДАЛЬНЕЙШЕЕ РЕДАКТИРОВАНИЕ

Посмотрите на эту ссылку: man traceroute

В разделе " Список доступных методов " вы можете найти множество способов добиться того, что вам нужно. Ваш метод похож на метод по умолчанию, заявив:

Зондовые пакеты - это дейтаграммы udp с так называемыми "маловероятными" портами назначения. "Невероятный" порт первого зонда - 33434, затем для каждого следующего зонда он увеличивается на единицу. Поскольку предполагается, что порты не используются, хост назначения обычно возвращает "icmp unreach port" в качестве окончательного ответа. (Никто не знает, что происходит, когда какое-либо приложение прослушивает такие порты).

Итак, если вам нужно полностью эмулировать поведение обычной трассировки Linux, вам нужно увеличить на 1 порт назначения каждый раз, когда увеличивается TTL (или каждый раз, когда вы не можете получить ответ IMHO)

МОЖЕТ, иногда ваша команда не работает на определенных портах, потому что маршрутизатор прислушивается к последним (как предложено руководством Linux и подчеркнуто жирным шрифтом мной).

Другие вопросы по тегам