国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 網(wǎng)絡(luò)通信 > 正文

透析ICMP協(xié)議(五): 應(yīng)用篇路由追蹤

2019-11-04 12:09:01
字體:
供稿:網(wǎng)友

原理簡介:
--------
   通過前四節(jié)的介紹, 可能大家對ICMP的應(yīng)用有了初步的了解. 不過開始本節(jié)之前我對ICMP協(xié)議再從宏觀上做些介紹. 大家都知道ICMP是為于ISO的第三層---網(wǎng)絡(luò)層。 既是它同ip協(xié)議為于同一層, 然而大家可能也只到,ICMP協(xié)議要用到IP協(xié)議, 所以有一些書上說ICMP位ISO的第四層, 那是錯誤的。 同樣這樣那些書上這樣畫的的例子也是錯誤的, 我就發(fā)現(xiàn)某外資通訊公司的資料上有這樣兩種錯誤的畫法
   --------------------------       
   ICMP TCP(SCTP) 
   --------------------------
            IP                  
   --------------------------
  
   ---------------------------
   ...        TCP(SCTP)  
   ---------------------------
   ICMP    IP               
   ----------------------------

其實(shí)如上的畫法是錯誤的, 正確地畫法應(yīng)為:
   ---------------------       
   ...   TCP(SCTP)  
   ---------------------
   ICMP                 
   ----------               
          IP                 
   ---------------------

接下來,讓我們來說明怎樣實(shí)現(xiàn)追蹤路由的功能, 大家通過我的第一節(jié)的閱讀可能已經(jīng)了解了超時報文的具體內(nèi)容(參見透析ICMP協(xié)議(一):  協(xié)議原理), 它在假如網(wǎng)關(guān)在處理數(shù)據(jù)報時發(fā)現(xiàn)生存周期域(ttl)為零,此數(shù)據(jù)報必須拋棄。網(wǎng)關(guān)同時必須通過超時信息通知源主機(jī)。這是它的報文的具體結(jié)構(gòu):
    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        Type(11)       Code(0/1)           Checksum            
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                                unused                           
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         Internet Header + 64 bits of Original Data Datagram     
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


通過利用setsockopt()函數(shù)設(shè)置ICMP包的IP包頭中的ttl字段便可以達(dá)到這種效果。 具體過程如下, 假設(shè)你的IP到達(dá)目標(biāo)地址需要過n個路由器(n>1)。 則
1. 初始化第一個ICMP包,并設(shè)置IP包頭中的TTL為1, 則得到第一個數(shù)據(jù)路由器發(fā)回的超時報文
2. 一般情況下:初始化第i(i<n)個ICMP包,并設(shè)置IP包頭中的TTL為i, 則得到第一個數(shù)據(jù)路由器發(fā)回的超時報文

剩下的問題為如何確定超時ICMP報文的路由器IP地址得到它的機(jī)器名的信息。 這個問題可能很多讀者都會求, 用gethostbyaddr()可以得到答案。

經(jīng)過理論的論證后, 讓我們看看如何實(shí)現(xiàn)。
  

具體實(shí)現(xiàn):(具體如何初試化ICMP的數(shù)據(jù)包上節(jié)已有具體的介紹,這里只是補(bǔ)充路由追蹤的代碼)
--------
主要代碼如下:

unsigned long ipback = 0; //超時報文的IP的初試值
unsigned long ms = 0; //超時值
strUCt hostent *hHost;
char m_address[256];

//直到找到目標(biāo)主機(jī), 或達(dá)到最大跳數(shù)(HOPS)
while (ipback != ipfinal){ 
hHost = 0;


//對到目標(biāo)主機(jī)中間的某個路由器發(fā)放ping的報文(ttl為1~N-1之間)
if (Ping(m_address,ttl,ipback,ms))
{
  sin.sin_family = AF_INET;
  sin.sin_addr.S_un.S_addr = ipback; // 由函數(shù)返回的IP地址
    // 查找主機(jī)名
  hHost = gethostbyaddr((char*)&sin.sin_addr, 4, PF_INET);
  //這里可以輸出hHost的內(nèi)容
}
ttl++;
if (ttl > MAX_HOPS)  //達(dá)到最大跳數(shù)
{
  break;
}
}

==================
ping函數(shù)的代碼
==================
int Ping(const char * host, int ttl, unsigned long& ipback, unsigned long& ms)
{
SOCKET sockRaw;
struct sockaddr_in dest,from;
struct hostent * hp;
int bread,datasize;
int fromlen = sizeof(from);
int timeout = 100;
char *dest_ip;
char *icmp_data;
char *recvbuf;
unsigned int addr=0;
const int MAX_PACKET = 1024;

//初始化Socket
sockRaw = WSASocket (AF_INET,
      SOCK_RAW,
      IPPROTO_ICMP,
      NULL, 0, WSA_FLAG_OVERLAPPED);

if (sockRaw == INVALID_SOCKET)
{
  // 錯誤
}

   // 設(shè)置IP包頭的ttl字段
bread = setsockopt(sockRaw, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(int));
if(bread == SOCKET_ERROR)
{
  // 錯誤
}

// 設(shè)置接受超時為100ms
bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));
if(bread == SOCKET_ERROR)
{
  // 錯誤
}

//禁止用Nagle算法緩存數(shù)據(jù)
bread = setsockopt(sockRaw, SOL_SOCKET, TCP_NODELAY, (const char*)&killnagle, sizeof(int));
if (bread == SOCKET_ERROR)
{
  // 錯誤
}

timeout = 1000;
// 設(shè)置發(fā)送超時為100ms
bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,
       sizeof(timeout));
if(bread == SOCKET_ERROR)
{
  // 錯誤
}

//下面的代碼生成ICMP包
memset(&dest,0,sizeof(dest));
hp = gethostbyname(host);
if (!hp)
{
  addr = inet_addr(host);
}
if ((!hp)  && (addr == INADDR_NONE) )
{
  // 錯誤
}
if (hp != NULL)
  memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);
else
  dest.sin_addr.s_addr = addr;


//初始化dest
if (hp)
  dest.sin_family = hp->h_addrtype;
else
  dest.sin_family = AF_INET;

dest_ip = inet_ntoa(dest.sin_addr);

// 設(shè)置包長度
datasize = DEF_PACKET_SIZE;

// 計算包大小
datasize += sizeof(IcmpHeader); 

icmp_data = (char *)new[MAX_PACKET]; //分配內(nèi)存,可以用new 和 delete
recvbuf = (char *)new[MAX_PACKET];

if (!icmp_data)
{
  // 釋放內(nèi)存,退出
}

if (!recvbuf)
{
  // 釋放內(nèi)存,退出 }
}

memset(icmp_data,0,MAX_PACKET);
fill_icmp_data(icmp_data,datasize); // 這個函數(shù)用來填充ICMP的數(shù)據(jù)包

int bwrote;
((IcmpHeader*)icmp_data)->i_cksum = 0;
((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); // 存入當(dāng)前時間值
((IcmpHeader*)icmp_data)->i_seq = seq_no++;

// 計算校驗(yàn)和
((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, datasize);

  // 為了最后計算ICMP包回來的總時間
unsigned long tc = GetTickCount();
//發(fā)送數(shù)據(jù)包
bwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest, sizeof(dest));

if (bwrote == SOCKET_ERROR)
{
  // 錯誤
}
if (bwrote < datasize ) //發(fā)送字節(jié)數(shù)對否
{
}

// 接受數(shù)據(jù)包
bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from,
     &fromlen);
//計算總時間
ms = GetTickCount() - tc;

if (bread == SOCKET_ERROR)
{
  // 錯誤
}

// 得到返回的路由器
ipback = from.sin_addr.s_addr;

return 1;
}

===============================
函數(shù)fill_icmp_data()的源代碼
===============================
//這個結(jié)構(gòu)下面將用到
typedef struct _ihdr {
  BYTE i_type;
  BYTE i_code;
  USHORT i_cksum;
  USHORT i_id;
  USHORT i_seq;
  ULONG timestamp; /* 這不是ICMP包的一部分, 只是為了計算時間 */
}IcmpHeader;

void fill_icmp_data(char * icmp_data, int datasize){

  IcmpHeader *icmp_hdr;
  char *datapart;

  icmp_hdr = (IcmpHeader*)icmp_data; 

  icmp_hdr->i_type = ICMP_ECHO;
  icmp_hdr->i_code = 0;
  icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
  icmp_hdr->i_cksum = 0;
  icmp_hdr->i_seq = 0;
 
  datapart = icmp_data + sizeof(IcmpHeader);  //計算數(shù)據(jù)域的開始地址
  // 初試化數(shù)據(jù)域
  memset(datapart,'E', datasize - sizeof(IcmpHeader));

}



發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 蓬溪县| 滁州市| 阳原县| 安福县| 桑植县| 江山市| 张家川| 扶沟县| 陈巴尔虎旗| 措勤县| 肇东市| 廉江市| 大名县| 朔州市| 财经| 海安县| 赤壁市| 广南县| 那坡县| 安吉县| 彭阳县| 农安县| 施秉县| 驻马店市| 南和县| 桐柏县| 德安县| 鹤峰县| 贺州市| 清远市| 璧山县| 隆安县| 新干县| 栾城县| 凤城市| 三穗县| 鹤庆县| 房产| 大同市| 盘锦市| 房产|