NS3網絡仿真(12): ICMPv4協議
阿新 • • 發佈:2017-07-15
normal fun rac sequence icmp veh abcde all protoc
快樂蝦
http://blog.csdn.net/lights_joy/
歡迎轉載,但請保留作者信息
ICMP的全稱是 Internet ControlMessage Protocol 。
其目的就是讓我們可以檢測網絡的連通狀況。ICMP主要是透過不同的類別(Type)與代碼(Code) 讓機器來識別不同的連接狀況。本節利用NS3學習一下此協議。
1.1 報文格式
ICMP的報文格式例如以下:
即ICMP報文是IP報文的數據。而IPv4報文的格式例如以下:
在網上抓一個ping包來看看:
這是一個從192.168.24.1到192.168.24.129的ping包。再看看192.168.24.129的回應:
非常easy和前面的報文格式相應上。
1.2 用NS3生成ICMP的請求包
接下來試試用NS3生成上面的ICMP的請求包。
依照NS3數據包的生成規則,首先須要準備ICMP請求的數據部分,即報文中的abcde...:
// 填充的數據內容 uint8_t buffer[2048] = { 0 }; for (int i = 0; i < m_nCurPacketLen; i++) { buffer[i] = ‘a‘ + (i % 23); } Ptr<Packet> data = ns3::Create<Packet>(buffer, m_nCurPacketLen); 接下來填充Icmp Echo的包頭: // 生成要發送的數據包列表 Ptr<Packet> pkt = ns3::Create<Packet>(); // 加入icmp echo頭 Icmpv4Echo eh; eh.SetData(data); eh.SetSequenceNumber(0x0019/*m_nCurPacketSeq*/); eh.SetIdentifier(1); pkt->AddHeader(eh); 這裏的seq是一個可變的整數,僅僅只是我們為了與上面的數據包一致寫入了一個固定的數值。 接下來填充Icmp Header: // 加入icmp頭 Icmpv4Header ih; ih.SetCode(0); ih.SetType(Icmpv4Header::ECHO); ih.EnableChecksum(); pkt->AddHeader(ih); 這裏唯一須要註意的是EnableChecksum必須在AddHeader前調用,否則不會生成校驗和。 再加上IP包頭: // 加入IP頭 Ipv4Header iph; iph.SetDestination((const char*)dest_ip); iph.SetSource((const char*)src_ip); iph.SetIdentification(0x49fb); iph.SetTtl(64); iph.SetProtocol(Icmpv4L4Protocol::PROT_NUMBER); iph.SetPayloadSize(pkt->GetSize()); iph.EnableChecksum(); pkt->AddHeader(iph); 最後加上以太網包頭: // 加入以太網頭 EthernetHeader eeh; eeh.SetDestination((const char*)dest_mac); eeh.SetSource((const char*)src_mac); eeh.SetLengthType(ns3::Ipv4L3Protocol::PROT_NUMBER); pkt->AddHeader(eeh); int len = pkt->CopyData(buffer, 2048);
大功告成!看看我們生成的數據包內容:
與前面從網上抓下來的包一模一樣。
1.3 用NS3分析ICMP請求包
分析包的過程和構造包的過程剛好相反。從最外面的以太網包一直分析到數據:
/* Callback function invoked by libpcap for every incoming packet */ void CCommonIcmpSendDlg::packet_handler(void *_param, const void *_header, const void *_pkt_data) { uint8_t buffer[2048], *p; p = (uint8_t *)_pkt_data + 12; if (p[0] != 8 || p[1] != 0) return; const struct pcap_pkthdr *header = (const struct pcap_pkthdr *)_header; Ptr<Packet> pkt = ns3::Create<Packet>((uint8_t*)_pkt_data, header->len); // ip 包 EthernetHeader eh; Ipv4Header iph; pkt->RemoveHeader(eh); pkt->RemoveHeader(iph); if (iph.GetProtocol() != Icmpv4L4Protocol::PROT_NUMBER) return; Icmpv4Header ih; Icmpv4Echo ieh; SIcmpPacket* ppkt; pkt->RemoveHeader(ih); if (ih.GetType() == Icmpv4Header::ECHO_REPLY) { pkt->RemoveHeader(ieh); if (ieh.GetIdentifier() != dlg->m_nIcmpId) return; int seq = ieh.GetSequenceNumber(); ..... return; } }
1.4 winpcap發包的問題
在發送ICMP包時,使用了pcap_sendpacket函數進行發包,但此函數的發包延遲較大,從函數調用到從網卡上抓到這個包可以有幾百個毫秒的延遲。
暫且記下來以供後繼參考。
NS3網絡仿真(12): ICMPv4協議