啤酒花跟踪ttl在ios上重新开始

时间:2013-01-13 14:47:02

标签: ios c sockets network-programming ttl

我正在尝试为iOS实现简单的traceroute。一切似乎都运行良好,除了当我在模拟器或设备上运行我的应用程序时,它在CLI traceroute找到所有14个路由器的路上只发现了几个(6-7)第一个路由器。

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;
    }
  }
}

我试图绑定发送套接字,但结果相同,我不能在iOS上使用Sock_raw。我试着在我的Mac上运行它并获得相同的结果。我得到的错误是“资源暂时不可用;”对于recvfrom()。这是为什么?我该如何解决?

1 个答案:

答案 0 :(得分:3)

接收套接字的超时可能会引发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,然后对于每个下一个探针,它增加1。由于预计端口未使用,目标主机通常会返回“icmp unreach port”作为最终响应。 (没有人知道当某个应用程序侦听此类端口时会发生什么,但)。

因此,如果您需要完全模拟常见Linux traceroute的行为,则必须将目标端口增加1,每次TTL增加(或每次无法获得响应IMHO)

可能,有时你的命令在某些端口上不起作用,因为路由器正在监听后者(正如Linux手册所建议的那样,我用粗体加下划线)。