在IOS平臺(tái)實(shí)現(xiàn)Ping 和 traceroute

ping 命令

Ping是為了測(cè)試另一臺(tái)主機(jī)是否可達(dá),現(xiàn)在已經(jīng)成為一種常用的網(wǎng)絡(luò)狀態(tài)檢查工具。

常見(jiàn)的ping命令:

/**** 往目的追擊發(fā)送固定包數(shù) ****/
ping -c 3 www.baidu.com   // ping百度發(fā)送3個(gè)包

/**** 設(shè)置兩次發(fā)包之間的等待時(shí)間 ****/
ping -i 5 www.baidu.com   // 兩包之間的時(shí)間間隔為5s
ping -i 0.1 www.baidu.com // 兩包之間的時(shí)間間隔為0.1s

/**** 檢查本地網(wǎng)絡(luò)接口是否已經(jīng)啟動(dòng)并正在運(yùn)行  ****/
ping 127.0.0.1  (linux: ping 0) 
ping localhost 

/**** 超級(jí)用戶可以利用 -f 幾秒鐘發(fā)送數(shù)十萬(wàn)個(gè)包給主服務(wù)造成壓力 *****/
sudo ping -f www.baidu.com 

/**** 讓電腦發(fā)出蜂鳴聲: 響應(yīng)包到達(dá)目時(shí),會(huì)發(fā)出聲音  ****/
ping -a www.baidu.com 

/**** 只打印ping的匯總結(jié)果  ****/
ping -c 5 -q www.baidu.com

/**** 修改ping包(icmp包)的大小 ****/
ping -s 100 -c 5 www.baidu.com




示例:

macdeiMac:PhoneNetSDK ethan$ ping www.baidu.com

PING www.a.shifen.com (61.135.169.121): 56 data bytes
64 bytes from 61.135.169.121: icmp_seq=0 ttl=49 time=32.559 ms
64 bytes from 61.135.169.121: icmp_seq=1 ttl=49 time=32.413 ms
64 bytes from 61.135.169.121: icmp_seq=2 ttl=49 time=32.489 ms
^C
--- www.a.shifen.com ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 32.413/32.487/32.559/0.060 ms
macdeiMac:PhoneNetSDK ethan$ 

分析以上結(jié)果:

  • 發(fā)送端信息

    • www.a.shifen.com (61.135.169.121): 對(duì)域名做了自動(dòng)DNS解析
    • 56 data bytes: 向該主機(jī)發(fā)送大小是56字節(jié)的數(shù)據(jù)包。
  • 主機(jī)響應(yīng)的信息

    • icmp_seq: 響應(yīng)包的序列號(hào)。
    • ttl: ip數(shù)據(jù)報(bào)的ttl值。
    • time:請(qǐng)求往返耗時(shí)。
    • 64 bytes:響應(yīng)數(shù)據(jù)包的大小是64個(gè)字節(jié)。
  • 統(tǒng)計(jì)總結(jié)信息

    • 0.0% packet loss: 總共發(fā)了3個(gè)包丟包率是0%
    • min/avg/max = 32.413/32.487/32.559:最小/平均/最大往返時(shí)間32.413/32.487/32.559

TTL(Time to live): IP數(shù)據(jù)報(bào)的生存時(shí)間,單位是hop(跳)。比如64,每過(guò)一個(gè)路由器就把該值減1,如果減到0 就表示路由已經(jīng)太長(zhǎng)了仍然找不到目的主機(jī)的網(wǎng)絡(luò),就丟棄該包。

問(wèn)題:在發(fā)包時(shí),為什么發(fā)送的是56字節(jié)的包,主機(jī)響應(yīng)的卻是64字節(jié)的包? 在這里的56和64是同一個(gè)概念嗎?

icmp

互聯(lián)網(wǎng)控制消息協(xié)議(英語(yǔ):Internet Control Message Protocol,縮寫(xiě):ICMP)是互聯(lián)網(wǎng)協(xié)議族的核心協(xié)議之一。它是TCP/IP協(xié)議族的一個(gè)子協(xié)議,它用于TCP/IP網(wǎng)絡(luò)中發(fā)送控制消息,提供可能發(fā)生在通信環(huán)境中的各種問(wèn)題反饋,通過(guò)這些信息,使管理者可以對(duì)所發(fā)生的問(wèn)題作出診斷,然后采取適當(dāng)?shù)拇胧┙鉀Q。

控制消息有:目的不可達(dá)下次,超時(shí)信息,重定向消息,時(shí)間戳請(qǐng)求和時(shí)間戳響應(yīng)消息,回顯請(qǐng)求和回顯應(yīng)答消息。

ICMP [1]依靠IP來(lái)完成它的任務(wù),它是IP的主要部分。它與傳輸協(xié)議(如TCP和UDP)顯著不同:它一般不用于在兩點(diǎn)間傳輸數(shù)據(jù)。它通常不由網(wǎng)絡(luò)程序直接使用,除了ping和traceroute這兩個(gè)特別的例子。 IPv4中的ICMP被稱作ICMPv4,IPv6中的ICMP則被稱作ICMPv6。

icmp技術(shù)細(xì)節(jié)

CMP是在RFC 792中定義的互聯(lián)網(wǎng)協(xié)議族之一。通常用于返回的錯(cuò)誤信息或是分析路由。ICMP錯(cuò)誤消息總是包括了源數(shù)據(jù)并返回給發(fā)送者。 ICMP錯(cuò)誤消息的例子之一是TTL值過(guò)期。每個(gè)路由器在轉(zhuǎn)發(fā)數(shù)據(jù)報(bào)的時(shí)候都會(huì)把IP包頭中的TTL值減1。如果TTL值為0,“TTL在傳輸中過(guò)期”的消息將會(huì)回報(bào)給源地址。 每個(gè)ICMP消息都是直接封裝在一個(gè)IP數(shù)據(jù)包中的,因此,和UDP一樣,ICMP是不可靠的。

雖然ICMP是包含在IP數(shù)據(jù)包中的,但是對(duì)ICMP消息通常會(huì)特殊處理,會(huì)和一般IP數(shù)據(jù)包的處理不同,而不是作為IP的一個(gè)子協(xié)議來(lái)處理。在很多時(shí)候,需要去查看ICMP消息的內(nèi)容,然后發(fā)送過(guò)當(dāng)?shù)腻e(cuò)誤消息到那個(gè)原來(lái)產(chǎn)生IP數(shù)據(jù)包的程序,即那個(gè)導(dǎo)致ICMP信息被傳送的IP數(shù)據(jù)包。

很多常用的工具是基于ICMP消息的。traceroute是通過(guò)發(fā)送包含有特殊的TTL的包,然后接收ICMP超超消息和目標(biāo)不可達(dá)消息來(lái)實(shí)現(xiàn)的。ping則是用ICMP的”Echo request”(類(lèi)別代碼:8)和”Echo reply”(類(lèi)別代碼:0)消息來(lái)實(shí)現(xiàn)的。

icmp報(bào)文結(jié)構(gòu)

報(bào)頭

ICMP報(bào)頭從IP報(bào)頭的第160位開(kāi)始(ip首部20字節(jié))

image
  • Type: ICMP的類(lèi)型,標(biāo)識(shí)生成的錯(cuò)誤報(bào)文
  • Code: 進(jìn)一步割分ICMP的類(lèi)型,該字段用來(lái)查找產(chǎn)生錯(cuò)誤的原因;例如ICMP的目標(biāo)不可達(dá)類(lèi)型可以把這個(gè)位設(shè)置為1-15等來(lái)表示不同的意思。
  • Checksum : 校驗(yàn)碼部分,這個(gè)字段包含有從ICMP報(bào)頭和數(shù)據(jù)部分計(jì)算得來(lái),用于檢查錯(cuò)誤的數(shù)據(jù),其中此校驗(yàn)碼字段的值視為0
  • ID :這個(gè)字段包含了ID值,在Echo Reply類(lèi)型的消息中要返回這個(gè)字段
  • Sequence : 這個(gè)字段包含一個(gè)序號(hào),同樣要在Echo Reply類(lèi)型的消息中要返回這個(gè)字段

填充數(shù)據(jù)

填充的數(shù)據(jù)緊接在ICMP報(bào)頭的后面(以8位為一組):

  • Linux的ping工具填充的ICMP除了8個(gè)8位元組的報(bào)頭以外,默認(rèn)情況下還另外填充數(shù)據(jù)使得總大小位64字節(jié)。
  • Windows的ping.exe填充的ICMP除了8個(gè)8位元組的報(bào)頭以外,默認(rèn)情況下還另外填充數(shù)據(jù)使得總大小位40字節(jié)。

ping

ping實(shí)現(xiàn)原理

Ping是為了測(cè)試另一臺(tái)主機(jī)是否可達(dá),現(xiàn)在已經(jīng)成為一種常用的網(wǎng)絡(luò)狀態(tài)檢查工具。該程序發(fā)送一份 ICMP回顯請(qǐng)求報(bào)文給遠(yuǎn)程主機(jī),并等待返回 ICMP回顯應(yīng)答。

ping 使用的是ICMP協(xié)議,它發(fā)送icmp回送請(qǐng)求消息給目的主機(jī)。ICMP協(xié)議規(guī)定:目的主機(jī)必須返回ICMP回送應(yīng)答消息給源主機(jī)。如果源主機(jī)在一定時(shí)間內(nèi)收到應(yīng)答,則認(rèn)為主機(jī)可達(dá)。大多數(shù)的 TCP/IP 實(shí)現(xiàn)都在內(nèi)核中直接支持Ping服務(wù)器,ICMP回顯請(qǐng)求和回顯應(yīng)答報(bào)文如下圖所示。

image

ping的原理:

image

ping的原理是用類(lèi)型碼為8的ICMP發(fā)請(qǐng)求,收到請(qǐng)求的主機(jī)則用類(lèi)型碼為0的ICMP回應(yīng)。通過(guò)計(jì)算ICMP應(yīng)答報(bào)文數(shù)量和與接受與發(fā)送報(bào)文之間的時(shí)間差,判斷當(dāng)前的網(wǎng)絡(luò)狀態(tài)。這個(gè)往返時(shí)間的計(jì)算方法是:ping命令在發(fā)送ICMP報(bào)文時(shí)將當(dāng)前的時(shí)間值存儲(chǔ)在ICMP報(bào)文中發(fā)出,當(dāng)應(yīng)答報(bào)文返回時(shí),使用當(dāng)前時(shí)間值減去存放在ICMP報(bào)文數(shù)據(jù)中存放發(fā)送請(qǐng)求的時(shí)間值來(lái)計(jì)算往返時(shí)間。ping返回接收到的數(shù)據(jù)報(bào)文字節(jié)大小、TTL值以及往返時(shí)間。

利用wireshark查看ping

我在命令行中ping www.baidu.com 以下是顯示結(jié)果:

image
image

如上圖所示,icmp包的type是8 , 是request請(qǐng)求; icmp的包type是0 ,是reply.

計(jì)算機(jī)網(wǎng)絡(luò)基礎(chǔ)知識(shí)

TCP/IP協(xié)議棧與數(shù)據(jù)包封裝

OSI七層模型以及TCP/IP模型:

image

兩臺(tái)計(jì)算機(jī)通過(guò)TCP/IP的通信過(guò)程如下:

image

傳輸層及其以下的機(jī)制由內(nèi)核提供,應(yīng)用層由用戶進(jìn)程提供,應(yīng)用程序?qū)νㄓ崝?shù)據(jù)的含義進(jìn)行解釋,而傳輸層及其以下處理通訊的細(xì)節(jié),將數(shù)據(jù)從一臺(tái)計(jì)算機(jī)通過(guò)一定的路徑發(fā)送到另一臺(tái)計(jì)算機(jī)。應(yīng)用層數(shù)據(jù)通過(guò)協(xié)議棧發(fā)到網(wǎng)絡(luò)上時(shí),每層協(xié)議都要加上一個(gè)數(shù)據(jù)首部(header),稱為封裝(Encapsulation)。

TCP/IP數(shù)據(jù)包的封裝:

image

目的主機(jī)收到數(shù)據(jù)包后,經(jīng)過(guò)各層協(xié)議棧最后到達(dá)應(yīng)用程序。

image

以太網(wǎng)驅(qū)動(dòng)程序首先根據(jù)以太網(wǎng)首部中的“上層協(xié)議”字段確定該數(shù)據(jù)幀的有效載荷是IP、ARP還是RARP協(xié)議的數(shù)據(jù)報(bào),然后交給相應(yīng)的協(xié)議處理。假如是IP數(shù)據(jù)報(bào),IP協(xié)議再根據(jù)IP首部中的“上層協(xié)議”字段確定該數(shù)據(jù)報(bào)的有效載荷是TCP、UDP、ICMP還是IGMP,然后交給相應(yīng)的協(xié)議處理。假如是TCP段或UDP段,TCP或UDP協(xié)議再根據(jù)TCP首部或UDP首部的“端口號(hào)”字段確定應(yīng)該將應(yīng)用層數(shù)據(jù)交給哪個(gè)用戶進(jìn)程。IP地址是標(biāo)識(shí)網(wǎng)絡(luò)中不同主機(jī)的地址,而端口號(hào)就是同一臺(tái)主機(jī)上標(biāo)識(shí)不同進(jìn)程的地址,IP地址和端口號(hào)合起來(lái)標(biāo)識(shí)網(wǎng)絡(luò)中唯一的進(jìn)程。

注意,雖然IP、ARP和RARP數(shù)據(jù)報(bào)都需要以太網(wǎng)驅(qū)動(dòng)程序來(lái)封裝成幀,但是從功能上劃分,ARP和RARP屬于鏈路層,IP屬于網(wǎng)絡(luò)層。雖然ICMP、IGMP、TCP、UDP的數(shù)據(jù)都需要IP協(xié)議來(lái)封裝成數(shù)據(jù)報(bào),但是從功能上劃分,ICMP、IGMP與IP同屬于網(wǎng)絡(luò)層,TCP和UDP屬于傳輸層。

IP數(shù)據(jù)報(bào)格式

IPv4數(shù)據(jù)包格式如下:

image

關(guān)于首部長(zhǎng)度:

根據(jù)IP數(shù)據(jù)報(bào),判斷當(dāng)前包是否是IPv4


version占4位,首部長(zhǎng)度占4位,version = 4(IPv4), ipheader=20.
由于首部長(zhǎng)度是以4字節(jié)為單位的-> version: 0100 ; 首部長(zhǎng)度:0101

獲取version:  0100 0101 & 0xFO(11110000) = 01000000 = 0x40
獲取首部長(zhǎng)度:  0100 0101 & 0x0F(00001111) = 0000 0101 = 5個(gè)4字節(jié) = 20 Byte

ping實(shí)現(xiàn)(c++&oc)

技術(shù)預(yù)研與構(gòu)思

根據(jù)ping的結(jié)果,我們需要解決以下問(wèn)題:

macdeiMac:PhoneNetSDK ethan$ ping www.baidu.com

PING www.a.shifen.com (61.135.169.121): 56 data bytes
64 bytes from 61.135.169.121: icmp_seq=0 ttl=49 time=32.559 ms
64 bytes from 61.135.169.121: icmp_seq=1 ttl=49 time=32.413 ms
64 bytes from 61.135.169.121: icmp_seq=2 ttl=49 time=32.489 ms
^C
--- www.a.shifen.com ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 32.413/32.487/32.559/0.060 ms
macdeiMac:PhoneNetSDK ethan$ 
  • DNS解析(域名->ip)
  • 本地終端接收到的每個(gè)icmp包來(lái)自哪個(gè)主機(jī)
  • icmp_seq
  • ttl
  • time

以上問(wèn)題解決方案如下:

  • DNS解析: socket支持
  • 本地終端接收到的每個(gè)icmp包來(lái)自哪個(gè)主機(jī): ip包中的source
  • icmp_seq: icmp包中的 sequence number
  • ttl: ip包中的Time to live
  • time: 發(fā)送包和接收到包時(shí)的時(shí)間差

具體實(shí)現(xiàn)

IP包定義:

typedef struct PNetIPHeader {
    uint8_t versionAndHeaderLength;
    uint8_t differentiatedServices;
    uint16_t totalLength;
    uint16_t identification;
    uint16_t flagsAndFragmentOffset;
    uint8_t timeToLive;
    uint8_t protocol;
    uint16_t headerChecksum;
    uint8_t sourceAddress[4];
    uint8_t destinationAddress[4];
    // options...
    // data...
}PNetIPHeader;

ICMP包定義:

/*
 use linux style . totals 64B
 */
typedef struct UICMPPacket
{
    uint8_t type;
    uint8_t code;
    uint16_t checksum;
    uint16_t identifier;
    uint16_t seq;
    char fills[56];  // data
}UICMPPacket;

構(gòu)造ICMP包:

+ (UICMPPacket *)constructPacketWithSeq:(uint16_t)seq andIdentifier:(uint16_t)identifier
{
    UICMPPacket *packet = (UICMPPacket *)malloc(sizeof(UICMPPacket));
    packet->type  = ENU_U_ICMPType_EchoRequest;
    packet->code = 0;
    packet->checksum = 0;
    packet->identifier = OSSwapHostToBigInt16(identifier);
    packet->seq = OSSwapHostToBigInt16(seq);
    memset(packet->fills, 65, 56);
    packet->checksum = [self in_cksumWithBuffer:packet andSize:sizeof(UICMPPacket)];
    return packet;
}

發(fā)送icmp包:

 UICMPPacket *packet = [PhoneNetDiagnosisHelper constructPacketWithSeq:index andIdentifier:identifier];
        _sendDate = [NSDate date];
        ssize_t sent = sendto(socket_client, packet, sizeof(UICMPPacket), 0, (struct sockaddr *)&remote_addr, (socklen_t)sizeof(struct sockaddr));
        if (sent < 0) {
            log4cplus_warn("PhoneNetPing", "ping %s , send icmp packet error..\n",[self.host UTF8String]);
        }

接收icmp包:

 size_t bytesRead = recvfrom(socket_client, buffer, 65535, 0, (struct sockaddr *)&ret_addr, &addrLen);
  if ((int)bytesRead < 0) {
            [self reporterPingResWithSorceIp:self.host ttl:0 timeMillSecond:0 seq:0 icmpId:0 dataSize:0 pingStatus:PhoneNetPingStatusDidTimeout];
            res = YES;
        }else if(bytesRead == 0){
            log4cplus_warn("PhoneNetPing", "ping %s , receive icmp packet error , bytesRead=0",[self.host UTF8String]);
        }else{
            
            if ([PhoneNetDiagnosisHelper isValidPingResponseWithBuffer:(char *)buffer len:(int)bytesRead]) {
                
                UICMPPacket *icmpPtr = (UICMPPacket *)[PhoneNetDiagnosisHelper icmpInpacket:(char *)buffer andLen:(int)bytesRead];
                
                int seq = OSSwapBigToHostInt16(icmpPtr->seq);
                
                NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:_sendDate];
                
                int ttl = ((PNetIPHeader *)buffer)->timeToLive;
                int size = (int)(bytesRead-sizeof(PNetIPHeader));
                NSString *sorceIp = self.host;
                
                
//                NSLog(@"PhoneNetPing, ping %@ , receive icmp packet..\n",self.host );
                [self reporterPingResWithSorceIp:sorceIp  ttl:ttl timeMillSecond:duration*1000 seq:seq icmpId:OSSwapBigToHostInt16(icmpPtr->identifier) dataSize:size pingStatus:PhoneNetPingStatusDidReceivePacket];
                res = YES;
            }

從接收到的buffer中分離icmp包:

/* 從 ipv4 數(shù)據(jù)包中解析出icmp */
+ (char *)icmpInpacket:(char *)packet andLen:(int)len
{
    if (len < (sizeof(PNetIPHeader) + sizeof(UICMPPacket))) {
        return NULL;
    }
    const struct PNetIPHeader *ipPtr = (const PNetIPHeader *)packet;
    if ((ipPtr->versionAndHeaderLength & 0xF0) != 0x40 // IPv4
        ||
        ipPtr->protocol != 1) { //ICMP
        return NULL;
    }
    size_t ipHeaderLength = (ipPtr->versionAndHeaderLength & 0x0F) * sizeof(uint32_t);
    
    if (len < ipHeaderLength + sizeof(UICMPPacket)) {
        return NULL;
    }
    
    return (char *)packet + ipHeaderLength;
}

校驗(yàn)接收到的icmp包:

+ (BOOL)isValidPingResponseWithBuffer:(char *)buffer len:(int)len
{
    UICMPPacket *icmpPtr = (UICMPPacket *)[self icmpInpacket:buffer andLen:len];
    if (icmpPtr == NULL) {
        return NO;
    }
    uint16_t receivedChecksum = icmpPtr->checksum;
    icmpPtr->checksum = 0;
    uint16_t calculatedChecksum = [self in_cksumWithBuffer:icmpPtr andSize:len-((char*)icmpPtr - buffer)];
    
    return receivedChecksum == calculatedChecksum &&
    icmpPtr->type == ENU_U_ICMPType_EchoReplay &&
    icmpPtr->code == 0 &&
    OSSwapBigToHostInt16(icmpPtr->identifier)>=KPingIcmpIdBeginNum;;
}

TCP ping

當(dāng)有些服務(wù)器禁ping時(shí),可以選擇TCP ping。

TCP ping原理

image

通過(guò)和目的主機(jī)及其端口建立TCP連接的方式計(jì)算其連接耗時(shí)。

traceroute

traceroute命令

/**** 設(shè)置每個(gè)路由發(fā)送的包數(shù) ****/
traceroute -q 5 baidu.com

/**** 設(shè)置最大路由跳數(shù) ****/
traceroute -m 5 baidu.com

/**** 不做DNS解析 ****/
traceroute -n baidu.com

/**** 繞過(guò)路由表直接發(fā)送到目的治具 ****/
traceroute -r baidu.com

/**** 使用ICMP包取代UDP包 ****/
traceroute -I baidu.com

traceroute原理

tacceroute是利用增加存活時(shí)間(TTL)值來(lái)實(shí)現(xiàn)功能的。每當(dāng)一個(gè)icmp包經(jīng)過(guò)一個(gè)路由器時(shí),其存活時(shí)間值就會(huì)減1,當(dāng)其存活時(shí)間為0時(shí),路由器便會(huì)取消包發(fā)送,并發(fā)送一個(gè)ICMP TTL封包給原封包發(fā)出者。

image

traceroute過(guò)程

主叫方首先發(fā)出TTL = 1 的數(shù)據(jù)包,第一個(gè)路由器將 TTL 減1得0后就不再繼續(xù)轉(zhuǎn)發(fā)此數(shù)據(jù)包,而是返回一個(gè)ICMP超時(shí)報(bào)文,主叫方從超時(shí)報(bào)文中即可提取出數(shù)據(jù)包所經(jīng)過(guò)的第一個(gè)路由器的地址。然后又發(fā)出一個(gè)TTL=2的ICMP數(shù)據(jù)包,可獲得第二個(gè)路由器的地址,依次增加TTL便獲取了沿途所有路由器位地址。

需要注意的是,并不是所有路由器都會(huì)如實(shí)返回ICMP超時(shí)報(bào)文。出于安全性考慮,大多數(shù)防火墻以及啟動(dòng)了防火墻功能的路由器缺省配置為不返回各種ICMP報(bào)文,其路由器或交換機(jī)也可被管理員主動(dòng)修改配置變?yōu)椴环祷豂CMP報(bào)文。因此Traceroute程序不一定能拿全所有沿途路由器地址。所以當(dāng)某個(gè)TTL值的數(shù)據(jù)包得不到響應(yīng)是,并不能停止這一追蹤過(guò)程,程序仍然會(huì)把TTL遞增而發(fā)出下一個(gè)數(shù)據(jù)包。一直達(dá)到預(yù)設(shè)或用于參數(shù)制定的追蹤限制時(shí)才結(jié)束追蹤。

依據(jù)上述原理,利用了UDP數(shù)據(jù)包的Traceroute程序在數(shù)據(jù)包到達(dá)真正的目的主機(jī)時(shí),就可能因?yàn)樵撝鳈C(jī)沒(méi)有提供UDP服務(wù)而簡(jiǎn)單將數(shù)據(jù)包丟棄,并不返回任何信息。為了解決這個(gè)問(wèn)題,Traceroute故意使用了一個(gè)大于30000的端口號(hào),因UDP協(xié)議規(guī)定端口號(hào)必須小于30000,所以目標(biāo)主機(jī)收到數(shù)據(jù)包后唯一能做的事就是返回一個(gè)"端口不可達(dá)"的ICMP報(bào)文,于是主叫方就將端口不可達(dá)報(bào)文當(dāng)做跟蹤結(jié)束標(biāo)志。

利用wireshark查看traceroute

我在命令行中traceroute www.baidu.com 以下是顯示結(jié)果:

image

如上圖所示,UDP請(qǐng)求,第一個(gè)請(qǐng)求的端口是33435 , 接下來(lái)的UDP請(qǐng)求,端口會(huì)遞增。

當(dāng)?shù)竭_(dá)目的地址時(shí),目的地址會(huì)replay類(lèi)型為3的包.

image

如上圖所示,是路由器返回的ICMP包,type是11。

UDP traceroute的實(shí)現(xiàn)

發(fā)送udp包,接收ip+icmp包,過(guò)濾route ip計(jì)算時(shí)間。

https://github.com/mediaios/net-diagnosis/tree/master/PhoneNetSDK/PhoneNetSDK/udptracert

UDP traceroute存在的問(wèn)題

使用 UDP 的 traceroute,失敗還是比較常見(jiàn)的。這常常是由于,在運(yùn)營(yíng)商的路由器上,UDP 與 ICMP 的待遇大不相同。為了利于 troubleshooting,ICMP 的request 和 replay 是不會(huì)封的,而 UDP 則不同。UDP 常被用來(lái)做網(wǎng)絡(luò)攻擊,因?yàn)?UDP 無(wú)需連接,因而沒(méi)有任何狀態(tài)約束它,比較方便攻擊者偽造源 IP、偽造目的端口發(fā)送任意多的 UDP 包,長(zhǎng)度自定義。所以運(yùn)營(yíng)商為安全考慮,對(duì)于 UDP 端口常常采用白名單 ACL,就是只有 ACL 允許的端口才可以通過(guò),沒(méi)有明確允許的則統(tǒng)統(tǒng)丟棄。比如允許 DNS/DHCP/SNMP 等。

icmp traceroute

發(fā)送icmp包,類(lèi)型為8,每個(gè)路由返回的icmp包類(lèi)型是11的超時(shí)包,當(dāng)?shù)竭_(dá)目的地址時(shí),目的地址會(huì)replay類(lèi)型為0的包

image

icmp traceroute的實(shí)現(xiàn)

https://github.com/mediaios/net-diagnosis/tree/master/PhoneNetSDK/PhoneNetSDK/utracert

net-diagnosis(ios平臺(tái)下網(wǎng)絡(luò)診斷SDK)

net-diagnosis是ios平臺(tái)下的網(wǎng)絡(luò)診斷SDK,提供的功能有:

  • ping
  • tcp ping
  • traceroute
  • icmp traceroute
  • nslookup
  • port scan

項(xiàng)目地址: github

后續(xù)更多關(guān)于網(wǎng)絡(luò)診斷的功能會(huì)不斷開(kāi)發(fā)完善,歡迎提交issue

另,歡迎fork和star !

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、TCP為什么需要3次握手,4次斷開(kāi)? “三次握手”的目的是“為了防止已失效的連接請(qǐng)求報(bào)文段突然又傳送到了服務(wù)端...
    杰倫哎呦哎呦閱讀 3,630評(píng)論 0 6
  • 個(gè)人認(rèn)為,Goodboy1881先生的TCP /IP 協(xié)議詳解學(xué)習(xí)博客系列博客是一部非常精彩的學(xué)習(xí)筆記,這雖然只是...
    貳零壹柒_fc10閱讀 5,180評(píng)論 0 8
  • 8.1 引言 由Van Jacobson編寫(xiě)的Traceroute程序是一個(gè)能更深入探索TCP/IP協(xié)議的方便可用...
    張芳濤閱讀 1,797評(píng)論 0 3
  • 本篇結(jié)構(gòu): ICMP IGMP 附 反思 接著上一篇TCP/IP--劃分子網(wǎng)和構(gòu)造超網(wǎng),本章接著分享IP協(xié)議的兩個(gè)...
    w1992wishes閱讀 11,258評(píng)論 0 4
  • 有種電影,我們目前只能“蹭”。 我們需要它,但我們又拍不來(lái)—— 《人生密密縫》 彼らが本気で編むときは、 今年2月...
    Sir電影閱讀 2,105評(píng)論 8 42

友情鏈接更多精彩內(nèi)容