這時候主機A
學到了主機B
的MAC
,就把這個MAC
封裝到ICMP
協議的二層報文中向主機B
發送,報文格式如下:
目的地址源地址源IP目的IPICMP報文 00-50-56-C0-00-0300-50-56-C0-00-011.1.1.11.1.1.3Echo request
當主機B
收到了這個報文後,發現是主機A
的ICPM
回顯請求,就按 同樣 的格式,返回一個值給主機A
,這樣就完成了 同一網段內 的ping
過程~~
目的地址源地址源IP目的IPICMP報文 00-50-56-C0-00-0100-50-56-C0-00-031.1.1.31.1.1.1Echo answer
而實際上,我囉嗦了這麼久的的區域網內的PING
,實際過程的發生不到 1毫秒 ~~
不同網段
主機A
要ping
主機C
,那麼主機A
發現主機C
的IP
和自己 不是 同一網段。
主機A
就去找 網關 轉發,但是他也不知道網關的MAC
情況下呢?
他就會向之前那個步驟一樣先發送一個ARP
廣播,學到網關的MAC
,再發封裝ICMP
報文給 網關路由器 。
報文格式如下:
目的地址源地址源IP目的IPICMP報文 00-50-56-C0-00-0200-50-56-C0-00-011.1.1.12.1.1.3Echo 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目的IPICMP報文 00-50-56-C0-00-0500-50-56-C0-00-041.1.1.12.1.1.1Echo request
最後,在主機C
已學到路由器2
埠MAC
,路由器2
埠轉發給路由器1
埠。
路由1
埠學到主機A
的MAC
的情況下,他們就不需要再做ARP
解析,就將ICMP
的回顯請求回復過來..
目的地址源地址源IP目的IPICMP報文 00-50-56-C0-00-0400-50-56-C0-00-052.1.1.11.1.1.1Echo Answer
代碼篇
既然已經明白了ping
命令和ICMP
的原理,那麼我們就可以用代碼 來實現 自動化 工具~~~
趙四.尼古拉斯基 曾經說過:不要重複造輪子 。
那麼,我們來介紹一下Python
處理網路協議
的 網路層 、傳輸層 、鏈路層 的能手 scapy
,和 爬蟲框架 scrapy
表兄弟關係,開個玩笑~~
Scapy 介紹Scapy 是一個可以讓用戶 發送 、偵聽 和 解析 並偽裝網路報文的Python
程序。這些功能可以用於製作 偵測 、掃描 和 攻擊網路 的工具。
安裝pip3 install scapy
API
建立一個數據包>>> 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.ttl64
堆加層次(網路5層模型)/ 操作符在兩層之間起到一個 組合 的作用。當使用該操作符時,下層 可以根據其 上層 ,使它的 一個 或 多個 默認欄位被重載。
(您仍可以賦予您想要的值)一個字元串也可以被用作原料層(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
"<IP frag=0 proto=TCP |<TCP |<Raw load=GET / HTTP/1.0
|>>>>>> 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="http://www. slashdot.org ")/TCP()/"GET /index.html HTTP/1.0
" >>> 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 [email protected] <....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 x00x02x157xa2Dx00xaexf3Rxaaxd1x08x00Ex00x00Cx00x01x00x00@x06x<xc0 xa8x05x15B#xfax97x00x14x00Px00x00x00x00x00x00x00x00Px02 x00 xbb9x00x00GET /index.html HTTP/1.0
原理 和API
都明白啦,是時候表演我們 真正的技術 啦
1. 構建一個ICMP包
2. 發送並且接受目的主機的回應
3. 如果目的主機可達,已```3```為結束碼並退出進程
這個時候我們就可以通過Python
構建了一個探測工具,判斷目的主機的網路連通性。
但僅僅如此還不夠智能,我們需要加入多進程掃描整個網路中的活動主機,所以:
通過要掃描的IP
,計算出當前區域網
的所有主機
多線程調用之前我們的探測工具,循環探測網路中的每個主機
講能夠連通的主機保存下來
為後面我們要做的事情做鋪墊
關注【mindev 】,回復【ping 】可以獲取單進程ping的源代碼, 加入羣主星球即可獲取所有源代碼。
願意與大家分享交流各種技術,個人公眾賬號[mindev],以及 知識星球[ 極客世界]
歡迎訂閱公眾賬號,日更喲~~~
推薦閱讀: