2016-01-26 34 views
1

我正在C中創建一個使用套接字編程的跟蹤路由的實現,它使用遞增的TTL字段創建新的請求。下面顯示的代碼工作得相當好,但是當嘗試聯繫google時,例如,recvfrom函數會掛起某些地址而不是其他地址,從而阻止算法完成並使程序無限運行。這是我到目前爲止有:recvfrom在某些地址掛起C

int traceroute(char *srcaddress) { 
int exists = 0; 
int sendsock, recvsock, portno, portno2, *ttl, i = 1; 
portno = 33434; 
portno2 = 33435; 
struct sockaddr_in recvaddr, sendaddr, curraddr, target; 
char *currAddr = myaddress; 
char message[512]; 
char *probemessage = "hello"; 
target.sin_addr.s_addr = inet_addr(srcaddress); 
target.sin_family = AF_INET; 
target.sin_port = 33436; 
ttl = &i; 
recvaddr.sin_family = AF_INET; 
recvaddr.sin_port = portno; 
recvaddr.sin_addr.s_addr = INADDR_ANY; 
sendaddr.sin_family = AF_INET; 
sendaddr.sin_port = portno2; 
sendaddr.sin_addr.s_addr = INADDR_ANY; 
while (i <= 30) { 

    sendsock = socket(AF_INET, SOCK_DGRAM, 0); 
    recvsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 
    if (sendsock < 0) { 
     exists = 1; 

     fprintf(stderr, "could not create sending socket"); 
    } 
    if (recvsock < 0) { 
     fprintf(stderr, "could not create receiving socket"); 
    } 
    setsockopt(sendsock, IPPROTO_IP, IP_TTL, ttl, sizeof(ttl)); 

    struct timeval tv; 

    tv.tv_sec = 1; /* 30 Secs Timeout */ 
    tv.tv_usec = 0; // Not init'ing this can cause strange errors 

    setsockopt(recvsock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval)); 


    int len = sizeof(curraddr); 

    if (bind(recvsock, (struct sockaddr *) &recvaddr, sizeof(recvaddr)) 
      < 0) { 
     fprintf(stderr, "could not bind"); 
    } 
    if (sendto(sendsock, probemessage, strlen(probemessage), 0, 
      (struct sockaddr*) &target, sizeof(target)) < 0) { 
     puts("did not send[100] data"); 
    } 
    if (recvfrom(recvsock, message, sizeof(message), 0, 
      (struct sockaddr*) &curraddr, (socklen_t*) &len) < 0) { 
     puts("no data receievd"); 
    } 
    currAddr = strdup(inet_ntoa(curraddr.sin_addr)); 
    if (strcmp(currAddr, srcaddress) == 0) { 
     break; 
    } 
    close(sendsock); 
    close(recvsock); 

    printf("hops: %d address %s \n", i, currAddr); 

    i++; 
} 
if (*ttl == 30 && currAddr != srcaddress) { 
    exists = 0; 
} else { 
    exists = 1; 
} 
return exists; 

}

在谷歌的例子,它會掛在當前地址62.72.134.198

UPDATE

我現在有實現了超時,但算法仍然沒有超過這些地址,似乎也沒有檢測到中間節點。我已經與現有的跟蹤路由的Linux實現交叉引用,即使跳數等於達到目標地址所需的數量,它似乎也不能接收任何數據。

這裏是二進制的strace的:

execve("./a.out", ["./a.out"], [/* 18 vars */]) = 0 
brk(0)         = 0x9b1c000 
access("/etc/ld.so.nohwcap", F_OK)  = -1 ENOENT (No such file or directory) 
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7797000 
access("/etc/ld.so.preload", R_OK)  = -1 ENOENT (No such file or directory) 
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 
fstat64(3, {st_mode=S_IFREG|0644, st_size=95669, ...}) = 0 
mmap2(NULL, 95669, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb777f000 
close(3)        = 0 
access("/etc/ld.so.nohwcap", F_OK)  = -1 ENOENT (No such file or directory) 
open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\210\1\0004\0\0\0"..., 512) = 512 
fstat64(3, {st_mode=S_IFREG|0755, st_size=1807496, ...}) = 0 
mmap2(NULL, 1814236, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb75c4000 
mmap2(0xb7778000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b3000) = 0xb7778000 
mmap2(0xb777d000, 7900, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb777d000 
close(3)        = 0 
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb75c3000 
set_thread_area({entry_number:-1 -> 6, base_addr:0xb75c3940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 
mprotect(0xb7778000, 12288, PROT_READ) = 0 
mprotect(0x8049000, 4096, PROT_READ) = 0 
mprotect(0xb77be000, 4096, PROT_READ) = 0 
munmap(0xb777f000, 95669)    = 0 
socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 3 
socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 4 
setsockopt(3, SOL_IP, IP_TTL, [1], 4) = 0 
setsockopt(4, SOL_SOCKET, SO_RCVTIMEO, "\1\0\0\0\0\0\0\0", 8) = 0 
bind(4, {sa_family=AF_INET, sin_port=htons(39554), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 
sendto(3, "hello", 5, 0, {sa_family=AF_INET, sin_port=htons(40066), sin_addr=inet_addr("192.168.1.244")}, 16) = 5 
recvfrom(4, "E\300\0=+_\0\[email protected]\1\311h\300\250\1\364\300\250\1\364\3\3\16Q\0\0\0\0E\0\0!"..., 512, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("192.168.1.244")}, [16]) = 61 
brk(0)         = 0x9b1c000 
brk(0x9b3d000)       = 0x9b3d000 
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 3), ...}) = 0 
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7796000 
write(1, "TEST PASSED\n", 12)   = 12 
socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 5 
socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 6 
setsockopt(5, SOL_IP, IP_TTL, [1], 4) = 0 
setsockopt(6, SOL_SOCKET, SO_RCVTIMEO, "\1\0\0\0\0\0\0\0", 8) = 0 
bind(6, {sa_family=AF_INET, sin_port=htons(39554), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 
sendto(5, "hello", 5, 0, {sa_family=AF_INET, sin_port=htons(40066), sin_addr=inet_addr("204.79.197.200")}, 16) = 5 
recvfrom(6, "E\300\0=\234A\0\[email protected]\1Yy\300\250\1\1\300\250\1\364\v\0I\323\0\0\0\0E\0\0!"..., 512, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("192.168.1.1")}, [16]) = 61 
close(5)        = 0 
close(6)        = 0 
write(1, "hops: 1 address 192.168.1.1 \n", 29) = 29 
socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 5 
socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 6 
setsockopt(5, SOL_IP, IP_TTL, [2], 4) = 0 
setsockopt(6, SOL_SOCKET, SO_RCVTIMEO, "\1\0\0\0\0\0\0\0", 8) = 0 
bind(6, {sa_family=AF_INET, sin_port=htons(39554), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 
sendto(5, "hello", 5, 0, {sa_family=AF_INET, sin_port=htons(40066), sin_addr=inet_addr("204.79.197.200")}, 16) = 5 
recvfrom(6, "E\0\0008\0\0\0\0\376\0013\264>H\210,\300\250\1\364\v\0\215\245\0\0\0\0E\0\0!"..., 512, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("62.72.136.44")}, [16]) = 56 
close(5)        = 0 
close(6)        = 0 
write(1, "hops: 2 address 62.72.136.44 \n", 30) = 30 
socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 5 
socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 6 
setsockopt(5, SOL_IP, IP_TTL, [3], 4) = 0 
setsockopt(6, SOL_SOCKET, SO_RCVTIMEO, "\1\0\0\0\0\0\0\0", 8) = 0 
bind(6, {sa_family=AF_INET, sin_port=htons(39554), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 
sendto(5, "hello", 5, 0, {sa_family=AF_INET, sin_port=htons(40066), sin_addr=inet_addr("204.79.197.200")}, 16) = 5 
recvfrom(6, "E\0\0`{\n\0\0\374\1\[email protected]>H\211m\300\250\1\364\v\0B/?\363\307\260E\0\0!"..., 512, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("62.72.137.109")}, [16]) = 96 
close(5)        = 0 
close(6)        = 0 
write(1, "hops: 3 address 62.72.137.109 \n", 31) = 31 
socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 5 
socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 6 
setsockopt(5, SOL_IP, IP_TTL, [4], 4) = 0 
setsockopt(6, SOL_SOCKET, SO_RCVTIMEO, "\1\0\0\0\0\0\0\0", 8) = 0 
bind(6, {sa_family=AF_INET, sin_port=htons(39554), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 
sendto(5, "hello", 5, 0, {sa_family=AF_INET, sin_port=htons(40066), sin_addr=inet_addr("204.79.197.200")}, 16) = 5 
recvfrom(6, "E\0\0`{\v\0\0\374\1\271?>H\211m\300\250\1\364\v\0B/?\363\307\260E\0\0!"..., 512, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("62.72.137.109")}, [16]) = 96 
close(5)        = 0 
close(6)        = 0 
write(1, "hops: 4 address 62.72.137.109 \n", 31) = 31 
socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 5 
socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 6 
setsockopt(5, SOL_IP, IP_TTL, [5], 4) = 0 
setsockopt(6, SOL_SOCKET, SO_RCVTIMEO, "\1\0\0\0\0\0\0\0", 8) = 0 
bind(6, {sa_family=AF_INET, sin_port=htons(39554), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 
sendto(5, "hello", 5, 0, {sa_family=AF_INET, sin_port=htons(40066), sin_addr=inet_addr("204.79.197.200")}, 16) = 5 
recvfrom(6, "E\0\0`\2263\0\0\374\1\240\276>H\206\306\300\250\1\364\v\0I\302\0\21\0\0E\0\0!"..., 512, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("62.72.134.198")}, [16]) = 96 
close(5)        = 0 
close(6)        = 0 
write(1, "hops: 5 address 62.72.134.198 \n", 31) = 31 
socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 5 
socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 6 
setsockopt(5, SOL_IP, IP_TTL, [6], 4) = 0 
setsockopt(6, SOL_SOCKET, SO_RCVTIMEO, "\1\0\0\0\0\0\0\0", 8) = 0 
bind(6, {sa_family=AF_INET, sin_port=htons(39554), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 
sendto(5, "hello", 5, 0, {sa_family=AF_INET, sin_port=htons(40066), sin_addr=inet_addr("204.79.197.200")}, 16) = 5 
recvfrom(6, "E\0\0008\0\0\0\0\373\1YY\303B\340\214\300\250\1\364\v\0\215\245\0\0\0\0E\0\0!"..., 512, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("195.66.224.140")}, [16]) = 56 
close(5)        = 0 
close(6)        = 0 
write(1, "hops: 6 address 195.66.224.140 \n", 32) = 32 
socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 5 
socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 6 
setsockopt(5, SOL_IP, IP_TTL, [7], 4) = 0 
setsockopt(6, SOL_SOCKET, SO_RCVTIMEO, "\1\0\0\0\0\0\0\0", 8) = 0 
bind(6, {sa_family=AF_INET, sin_port=htons(39554), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 
sendto(5, "hello", 5, 0, {sa_family=AF_INET, sin_port=htons(40066), sin_addr=inet_addr("204.79.197.200")}, 16) = 5 
recvfrom(6, "E\0\0008\[email protected]\0\371\0016\271\203\375\6\7\300\250\1\364\v\0\215\245\0\0\0\0E\0\0!"..., 512, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("131.253.6.7")}, [16]) = 56 
close(5)        = 0 
close(6)        = 0 
write(1, "hops: 7 address 131.253.6.7 \n", 29) = 29 
socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 5 
socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 6 
setsockopt(5, SOL_IP, IP_TTL, [8], 4) = 0 
setsockopt(6, SOL_SOCKET, SO_RCVTIMEO, "\1\0\0\0\0\0\0\0", 8) = 0 
bind(6, {sa_family=AF_INET, sin_port=htons(39554), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 
sendto(5, "hello", 5, 0, {sa_family=AF_INET, sin_port=htons(40066), sin_addr=inet_addr("204.79.197.200")}, 16) = 5 
recvfrom(6, 0xbff3ab4c, 512, 0, 0xbff3ab2c, 0xbff3aae0) = -1 EAGAIN (Resource temporarily unavailable) 
write(1, "no data receievd\n", 17)  = 17 
close(5)        = 0 
close(6)        = 0 
write(1, "hops: 8 address 131.253.6.7 \n", 29) = 29 

它反覆經過這裏重複上一次recvfrom的。

+0

請更新相應的代碼片段 – Ctx

+0

您可以使用'strace'運行您的二進制文件並提供它掛起的行嗎? – Ctx

+0

我編輯了問題,以便strace現在也在 – PaddyOsmond

回答

1

這很可能是有問題的跳躍不會生成ICMP_TIMXCEED消息。

有幾個原因,這可能會發生:

  • 率跳
  • 行政禁用限制
  • 過濾別處路徑

您需要實現在您的原始套接字處理程序中的「讀取超時」來檢測,最容易使用setsockopt(recvsock, SO_TIMEOUT, ...)

+0

我明白了,你想介紹一下嗎?它是否僅僅是一個爲超時值添加另一個setsocketopt的發送套接字的情況? – PaddyOsmond

+0

@ PaddyOsmond我還沒有嘗試過使用原始套接字,但我希望這是做到這一點的正確方法(但在讀取套接字上,而不是發送套接字) – Alnitak

1

跳數不保證發送ICMP不可達消息,有些根本不會發送,有些對生成此類消息有嚴格的速率限制。此外,目標可能會丟棄探測包而不回覆,所以你不知道何時到達目標(即ttl>跳數)。

所以你必須實現一個超時select()(e)poll()繼續發送您的探測器,如果一跳已超時。

除此之外,更好的方法是在套接字上設置IP_RECVERR,使用recvmsg()進行讀取並從套接字的錯誤隊列中獲取icmp錯誤。這甚至應該在沒有root權限的情況下運行,因爲你只需要UDP而不需要原始套接字。但是,您仍然必須實現讀取超時。

+0

沒有必要使用'select()'或'poll()',除非同時處理多個數據包。一個簡單的套接字讀取超時就足夠了。不過,對於'IP_RECVERR'好主意,假設它是可移植的。 – Alnitak

+0

我在BSD派生系統上看不到任何'IP_RECVERR' – Alnitak