ping 這個名字來源於航海的聲納定位操做。其操做相似於聲納定位。只不過在網絡裏發送的是ICMP
數據包而不是聲波。該命令的目的是用於肯定 某個主機 是否可達,距離 當前主機 多遠。 html
其實,咱們2臺網絡設備互ping
,是有兩種case
的。web
如上圖,主機A,來ping
主機B,那麼主機A,就要封裝 二層報文 ,他會先查本身的MAC
地址表,若是沒有B的MAC
地址,就會向外發送一個ARP廣播包【在以前的網絡篇已經講的很清楚了,這裏再也不囉嗦】。 shell
交換機會收到這個報文後,交換機有學習MAC
地址的功能,因此他會檢索本身有沒有保存主機B
的MAC
。 微信
若是有,就返回給主機A
,若是沒有,就會向全部端口發送ARP
廣播,其它主機收到後,發現不是在找本身,就紛紛丟棄了該報文,不去理會。 網絡
直到主機B
收到了報文後,就當即相應,個人MAC
地址是多少,同時學到主機A
的MAC
地址,並按一樣的ARP
報文格式返回給主機A
,如圖:多線程
這時候主機A
學到了主機B
的MAC
,就把這個MAC
封裝到ICMP
協議的二層報文中向主機B
發送,報文格式以下:框架
目的地址 | 源地址 | 源IP | 目的IP | ICMP報文 |
---|---|---|---|---|
00-50-56-C0-00-03 | 00-50-56-C0-00-01 | 1.1.1.1 | 1.1.1.3 | Echo request |
當主機B
收到了這個報文後,發現是主機A
的ICPM
回顯請求,就按 一樣 的格式,返回一個值給主機A
,這樣就完成了 同一網段內 的ping
過程~~scrapy
目的地址 | 源地址 | 源IP | 目的IP | ICMP報文 |
---|---|---|---|---|
00-50-56-C0-00-01 | 00-50-56-C0-00-03 | 1.1.1.3 | 1.1.1.1 | Echo answer |
而實際上,我囉嗦了這麼久的的局域網內的PING
,實際過程的發生不到 1毫秒~~工具
主機A
要ping
主機C
,那麼主機A
發現主機C
的IP
和本身 不是 同一網段。學習
主機A
就去找 網關 轉發,可是他也不知道網關的MAC
狀況下呢?
他就會向以前那個步驟同樣先發送一個ARP
廣播,學到網關的MAC
,再發封裝ICMP
報文給 網關路由器 。
報文格式以下:
目的地址 | 源地址 | 源IP | 目的IP | ICMP報文 |
---|---|---|---|---|
00-50-56-C0-00-02 | 00-50-56-C0-00-01 | 1.1.1.1 | 2.1.1.3 | Echo request |
當 路由器 收到主機A
發過來的ICMP
報文。
發現本身的目的地址是其自己MAC
地址,根據目的的IP2.1.1.1
,查 路由表,發現2.1.1.1/24
的路由表項。
獲得一個 出口指針,去掉原來的MAC
頭部.加上本身的MAC
地址向主機C
轉發…
若是網關也沒有主機C
的MAC
地址,仍是要向前面一個步驟同樣,ARP
廣播一下便可相互學到….
路由器2
端口能學到主機C
的MAC
,主機C
也能學到路由器2
端口的MAC
..
報文格式以下:
目的地址 | 源地址 | 源IP | 目的IP | ICMP報文 |
---|---|---|---|---|
00-50-56-C0-00-05 | 00-50-56-C0-00-04 | 1.1.1.1 | 2.1.1.1 | Echo request |
最後,在主機C
已學到路由器2
端口MAC
,路由器2
端口轉發給路由器1
端口。
路由1
端口學到主機A
的MAC
的狀況下,他們就不須要再作ARP
解析,就將ICMP
的回顯請求回覆過來..
目的地址 | 源地址 | 源IP | 目的IP | ICMP報文 |
---|---|---|---|---|
00-50-56-C0-00-04 | 00-50-56-C0-00-05 | 2.1.1.1 | 1.1.1.1 | Echo Answer |
既然已經明白了ping
命令和ICMP
的原理,那麼咱們就能夠用代碼來實現 自動化 工具~~~
趙四.尼古拉斯基 曾經說過:不要重複造輪子 。
那麼,咱們來介紹一下Python
處理網絡協議
的 網絡層、傳輸層、鏈路層 的能手 scapy
,和 爬蟲框架 scrapy
表兄弟關係,開個玩笑~~
Scapy 是一個可讓用戶 發送、偵聽 和 解析 並假裝網絡報文的
Python
程序。這些功能能夠用於製做 偵測、掃描 和 攻擊網絡 的工具。
pip3 install scapy
複製代碼
>>> a=IP(ttl=10)
>>> a
< IP ttl=10 |>
>>> a.src
’127.0.0.1’
>>> a.dst="192.168.1.1"
>>> a
< IP ttl=10 dst=192.168.1.1 |>
>>> a.src
’192.168.8.14’
>>> del(a.ttl)
>>> a
< IP dst=192.168.1.1 |>
>>> a.ttl
64
複製代碼
raw layer
)。>>> IP()
<IP |>
>>> IP()/TCP()
<IP frag=0 proto=TCP |<TCP |>>
>>> Ether()/IP()/TCP()
<Ether type=0x800 |<IP frag=0 proto=TCP |<TCP |>>>
>>> IP()/TCP()/"GET / HTTP/1.0\r\n\r\n"
<IP frag=0 proto=TCP |<TCP |<Raw load='GET / HTTP/1.0\r\n\r\n' |>>>
>>> Ether()/IP()/IP()/UDP()
<Ether type=0x800 |<IP frag=0 proto=IP |<IP frag=0 proto=UDP |<UDP |>>>>
>>> IP(proto=55)/TCP()
<IP frag=0 proto=55 |<TCP |>>
複製代碼
>>> a=Ether()/IP(dst="www.slashdot.org")/TCP()/"GET /index.html HTTP/1.0 \n\n"
>>> hexdump(a)
00 02 15 37 A2 44 00 AE F3 52 AA D1 08 00 45 00 ...7.D...R....E.
00 43 00 01 00 00 40 06 78 3C C0 A8 05 15 42 23 .C....@.x<....B#
FA 97 00 14 00 50 00 00 00 00 00 00 00 00 50 02 .....P........P.
20 00 BB 39 00 00 47 45 54 20 2F 69 6E 64 65 78 ..9..GET /index
2E 68 74 6D 6C 20 48 54 54 50 2F 31 2E 30 20 0A .html HTTP/1.0 .
0A .
>>> b=str(a)
>>> b
'\x00\x02\x157\xa2D\x00\xae\xf3R\xaa\xd1\x08\x00E\x00\x00C\x00\x01\x00\x00@\x06x<\xc0
\xa8\x05\x15B#\xfa\x97\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00
\xbb9\x00\x00GET /index.html HTTP/1.0 \n\n'
複製代碼
原理 和API
都明白啦,是時候表演咱們 真正的技術 啦
1. 構建一個ICMP包
2. 發送而且接受目的主機的迴應
3. 若是目的主機可達,已3
爲結束碼並退出進程
Python
構建了一個探測工具,判斷目的主機的網絡連通性。
但僅僅如此還不夠智能,咱們須要加入多進程掃描整個網絡中的活動主機,因此:
P
,計算出當前區域網
的全部主機ping
的源代碼,加入羣主星球便可獲取全部源代碼。願意與你們分享交流各類技術,我的公衆帳號[mindev],以及 知識星球[極客世界]