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é))
- 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)文如下圖所示。
ping的原理:
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é)果:
如上圖所示,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模型:
兩臺(tái)計(jì)算機(jī)通過(guò)TCP/IP的通信過(guò)程如下:
傳輸層及其以下的機(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ù)包的封裝:
目的主機(jī)收到數(shù)據(jù)包后,經(jīng)過(guò)各層協(xié)議棧最后到達(dá)應(yīng)用程序。
以太網(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ù)包格式如下:
關(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原理
通過(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ā)出者。
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é)果:
如上圖所示,UDP請(qǐng)求,第一個(gè)請(qǐng)求的端口是33435 , 接下來(lái)的UDP請(qǐng)求,端口會(huì)遞增。
當(dāng)?shù)竭_(dá)目的地址時(shí),目的地址會(huì)replay類(lèi)型為3的包.
如上圖所示,是路由器返回的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的包
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 !