1,在直连的设备上进行ARP扫描,可以准确的判断出主机的状态,比PING扫描来的更块更准确,

      因为现在大多数的设备都已经禁止PING技术了。

2,ARP数据包分析

      ARP_Request包:

python实现arp探测 python arp扫描_mac地址

    因为是个ARP包,所以以太二层的dst是广播(FF:FF:FF:FF:FF:FF),源地址是出接口的mac地址。

    arp_request的操作码是1,arp_reply的操作码是2

    arp协议的源mac和ip是出接口的mac和ip,目的mac是00:00:00:00:00:00(这就是问题),目的ip就

    是要查询的ip,如果找到,则在回复包中就会作为源mac地址发送回来。

     ARP_Reply包:

python实现arp探测 python arp扫描_python_02

    arp_reply包就回答了arp_request包的问题,所以以太二层的源mac就成功回复方的mac地址,目标mac  就是给谁回的mac地址,arp协议中操作码为2,代表arp_reply,以及发送方的mac和ip,目的地址的mac 和IP。

3,使用scapy铸造ARP数据包

arp_request=Ether(dst='FF:FF:FF:FF:FF:FF')/ARP(op=1,hwdst='00:00:00:00:00:00',pdst='192.168.219.180')
    arp_request.show()可以查看铸造的包的信息。

 

python实现arp探测 python arp扫描_tcpip_03

    根据实际情况对包的数据进行填写,已达到所需要的要求。

4,发送3铸造的数据包

    应为这里铸造的包是一个以太二层的数据包,所以在发送该数据包的时候,应该使用srp()函数,

    srp()可以发送一个以太二层的数据包并等待回复,这里的回复是一个复杂的数据结构,这里对

    这个回复做简单的解释。


python实现arp探测 python arp扫描_tcpip_04

    这里srp函数的返回值是一个特殊的类,分为收到结果的包,和未收到结果的包。这里可以看到,

    srp将返回值做成了一个元组。arp[0]就是收到的数据包,在收到的数据包中,又是列表,列表

    中的每一元素都是有发送的数据包和接收到的数据包组成,arp[0].res可以产生这个列表作为一

    个清单。清单的第一个元素(就是第一个响应的数据包)的第二个位置就是保存的接收到的数据包。

    在此位置查看此包的hwsrc字段,就是问题的答案,就是目标的mac地址。

5,实现arp数据包铸造和发送的程序代码

#--------------------------------------------------------------------------------------------------------------------------------
#!/usr/bin/python3.4
# _*_ coding=utf-8 _*_

#   清除报错
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *

#构造发送数据包并接受响应函数,两个参数,一个IP地址,一个队列,默认为None
def arp_request(ip_address,queue=None):
    #发送二层数据帧
    result_raw=srp(Ether(dst='FF:FF:FF:FF:FF:FF')/ARP(op=1,hwdst='00:00:00:00:00:00'
                             ,pdst=ipaddress,timeout=1,verbose=False)
    try:
        #把响应的数据包对,产生清单
        result_list=result_raw[0].res
        #[0]第一组响应数据包
        #[1]接收到的包,[0]为发送的数据包
        #[1]ARP头部字段中的['hwsrc']字段,作为返回值返回
        if queue==None:
            return result_list[0][1].getlayer(ARP).fields['hwsrc']
        else:
            queue.put((ip_address,result_list[0][1].getlayer(ARP).fields['hwsrc']))
    except: 
        return
 if __name_=='__main__':
    import sys
    print(arp_request(sys.argv[1]))
#--------------------------------------------------------------------------------------------------------------------------------
这里使用队列是为了进程间的通信,在这个进程中将所有响应的ip地址和mac放入队列中
,然后再另外一个进程将其都出来,以此实现进程间的通信。

6,实现arp扫描

#!/usr/bin/python3.4
# _*_ coding=utf-8 _*_
import logging
logging.getLogger(''scapy.runtime'').setLevel(logging.ERROR)
import ipaddress
import time
from arp_request import arp_request
from multiprocessing import Process,Queue
def arp_scan(network):
    queue=Queue()
    net=ipaddress.ip_network(network)
    for ip in net:
        ip_addr=str(ip)
        arp_one=Process(target=arp_request,args=(ip_addr,queue))
        arp_one.start()
    time.sleep(2)
    ip_mac_list=[]
    while True:
        if queue.empty():
            break;
        else:
            ip,mac=queue.get()
            ip_mac_list.append((ip,mac))
    return ip_mac_list
if  __name__=='__main__':
    import sys
    active_ip_mac=arp_scan(sys.argv[1])
    print('活动IP与MAC地址如下:')
    for ip,mac in active_ip_mac:
        print(ip,mac)
    print('总个数为:'+str(len(active_ip_mac))