1. 程式人生 > >NS3網絡仿真(12): ICMPv4協議

NS3網絡仿真(12): ICMPv4協議

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.1192.168.24.129ping包。再看看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協議