一、什麼是ICMP
ICMP是Internet控制報文協議(Internet Control Message Protocol)的縮寫,是TCP/IP協議棧中的一個重要協議。
ICMP用於傳遞有關通信狀態、錯誤和網路擁塞等信息。它主要是為了幫助網路管理員診斷和解決網路問題。
二、ICMP協議結構
ICMP報文是放在IP數據報的數據部分中,它通常包括ICMP報頭和ICMP數據兩部分。
ICMP報頭一般包含以下欄位:
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 | Code | Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identifier | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
具體欄位含義:
- Type:指示ICMP報文類型,CP1是回顯請求,CP2是回顯應答。
- Code:對Type進行細分,類型為1時,Code可以是0(Echo Request)或8(Echo Reply)。
- Checksum:ICMP頭部和數據的16位的校驗和。計算校驗和時採用補碼求和的方式。
- Identifier:用於標識此請求的ID值。通常是惟一的,因此可以與其他回顯請求區分開來。
- Sequence Number:序列號值。可以將該欄位視為用於識別每個回顯請求的附加信息。
三、ICMP屬於哪一層協議
ICMP作為IP層的一個可選模塊,使用IP作為它的傳輸層協議。從這個角度來看,ICMP屬於網路層協議。
ICMP主要用於網路的控制與管理,在TCP/IP的體系結構中,應當歸類於網路層,但從實現方式上看,ICMP作為IP的協議擴展模塊,天然屬於IP層。
四、ICMP應用示例
下面是一個使用Python實現ICMP PING命令的示例:
import os, struct, socket, select, time
ICMP_ECHO_REQUEST = 8
def checksum(source_string):
sum = 0
count_to = (len(source_string) / 2) * 2
for count in xrange(0, count_to, 2):
this_val = ord(source_string[count + 1]) * 256 + ord(source_string[count])
sum = sum + this_val
sum = sum & 0xffffffff
if count_to > 16) + (sum & 0xffff)
sum = sum + (sum >> 16)
answer = ~sum
answer = answer & 0xffff
answer = answer >> 8 | (answer << 8 & 0xff00)
return answer
def receive_one_ping(icmp_socket, ID, timeout):
time_left = timeout
while True:
started_select = time.time()
ready_to_read = select.select([icmp_socket], [], [], time_left)
how_long_in_select = (time.time() - started_select)
if ready_to_read[0] == []: # Timeout
return
time_received = time.time()
rec_packet, addr = icmp_socket.recvfrom(1024)
icmp_header = rec_packet[20:28]
type, code, checksum, packet_ID, sequence = struct.unpack(
"bbHHh", icmp_header
)
# Filters out the echo request itself.
if type != ICMP_ECHO_REQUEST or packet_ID != ID:
continue
return time_received - started_select
def send_one_ping(icmp_socket, dest_addr, ID):
dest_addr = socket.gethostbyname(dest_addr)
my_checksum = 0
header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, my_checksum, ID, 1)
data = struct.pack("d", time.time())
my_checksum = checksum(header + data)
if os.name == "nt":
# 注意:不同的操作系統對於SOCK_RAW的定義不同
# 而我們需要通過socket.IPPROTO_ICMP來獲取其中的ICMP協議
protocol_type = socket.IPPROTO_ICMP
else:
protocol_type = socket.IPPROTO_ICMP
header = struct.pack(
"bbHHh", ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), ID, 1
)
packet = header + data
while packet:
# 發送數據報
sent = icmp_socket.sendto(packet, (dest_addr, 1))
packet = packet[sent:]
def ping(dest_addr, timeout=2, count=4):
icmp = socket.getprotobyname("icmp")
# 創建一個原始套接字
icmp_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)
my_ID = os.getpid() & 0xFFFF
for i in xrange(count):
send_one_ping(icmp_socket, dest_addr, my_ID)
delay = receive_one_ping(icmp_socket, my_ID, timeout)
if delay is None:
print("Timeout")
else:
print("Reply from {}: delay={:.3f}ms".format(dest_addr, delay * 1000))
time.sleep(1)
icmp_socket.close()
ping("www.baidu.com")
原創文章,作者:IZQCM,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/371721.html
微信掃一掃
支付寶掃一掃