Reputation: 21
I'm a beginner, but I am trying to make a network scanning utility that can filter MAC addresses for a specific need; The company I work for has network connected devices that are assigned MAC addresses based on serial numbers. I have found that the first 6 digits of the MAC address are the indicator of our brand. This I have made into a str below. The 4th field of the MAC address is a small range of constant numbers that indicate the model of the device. I have these ready but its essentially a few numbers like '14', '17,' etc.
I'm struggling to figure out a way to "filter" the MAC addresses that are retrieved from the scan and label them depending on the fields of the address. OR even better, only print IP's and Mac addresses that match the startswith(mac_key) and label the remaining objects according to their MAC address 4th field [9:11].
With a lot of reading and help, I've got this so far:
#!/usr/bin/env python
from scapy.all import ARP, Ether, srp
import socket
# importing main functions from Scapy and Socket
mac_key = '04:24:2f'
# Target value for first three fields of MAC address
hostname = socket.gethostname()
IPAddr = socket.gethostbyname(hostname)
target_ip = ("192.168.{}.0/24".format(IPAddr[6]))
# Assigning index value for third section of IP address
# To make third section of target_ip a variable determined by host
# "/24" denotes IP address spectrum for the ARP packet destination
arp = ARP (pdst=target_ip)
# Creating ARP packet assigned to "target_ip"
ether = Ether(dst="ff:ff:ff:ff:ff:ff")
# Creating Ether broadcast packet
# ff:ff:ff:ff:ff:ff MAC address indicates broadcasting
packet = ether/arp
# Stacking
result = srp(packet, timeout=5, verbose=3)[0]
# Defining result with timeout parameter
clients= []
# Client list to be finished below
for sent, received in result:
clients.append({'ip': received.psrc, 'mac': received.hwsrc})
# For each response, append ip and mac address to 'clients' list
print("Devices On This Network:")
print("IP" + " "*18+"MAC")
# Print table of accumulated data
for client in clients:
print("{:24} {}".format(client['ip'], client['mac'].startswith(mac_key)))
# Printing IP addresses and assosciated MACs from clients list
# With bool checking against mac_key
The image below is the result in terminal; the idea would be to only print lines that show a value of TRUE and to add a label based on field [9:11] of the MAC address ex: "Network Device Pro" where the TRUE bool appears, and completely omit the line where a FALSE bool is triggered.
EDIT: Well, I've turned this into a blog at this point. I managed to do exactly what I wanted to do, and I will provide the code below for anyone who is trying to do something similar. I am open to any suggestions to make this more 'pythonic' and improve performance / syntax. I do have one question for anyone who can offer some advice; I want to loop this code and append information to the rendered list and include a user input kill switch to finish it off. This way if a packet does not reach on the first scan, it will still be added to the list. Bonus points if you can offer a suggestion for this, as well as a way to remove entries that don't respond after a consecutive number of loops!!
#!/usr/bin/env python3
# coding: utf-8
#
#
#//////////////////////////////////
#----------------------------------
# ippy Network Scanning Utility
# ~ Daniel Johnston 2020 ~
#----------------------------------
#\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
#
#
print("Initializing Scan...")
from scapy.all import ARP, Ether, srp
import socket
# importing main functions from Scapy and Socket
mac_key = ('00:25:2f')
# Target value for first three fields of MAC address (Brand Identifier)
MTU_key = ('13','15','16','17')
GW_key = ('21')
ECC_key = ('26')
#------serial numbers)------#
#('13','15','16','17','21','26'#
#---------LEGEND------------#
#serial numbers[0:3] = 'MTU'
#serial numbers[4] = 'Gateway'
#serial numbers[5] = 'ECC'
#---------------------------#
hostname = socket.gethostname()
IPAddr = socket.gethostbyname(hostname)
target_ip = ("192.168.{}.0/24".format(IPAddr[6]))
# Assigning index value for third section of IP address
# To make third section of target_ip a variable determined by host
# "/24" denotes IP address spectrum for the ARP packet destination
def devsub(x):
if x.startswith(MTU_key, 9, 11):
print("{} {}".format('MTU', client['ip'],))
if x.startswith(GW_key, 9, 11):
print("{} {}".format('Gateway', client['ip'],))
if x.startswith(ECC_key, 9, 11):
print("{} {}".format('ECC', client['ip'],))
# Defining function to print associated IP addresses, of MAC address
# Matches(done later), and assigning a device name based on
# index[9:11] of MAC
arp = ARP (pdst=target_ip)
# Creating ARP packet assigned to "target_ip"
ether = Ether(dst="ff:ff:ff:ff:ff:ff")
# Creating Ether broadcast packet
# ff:ff:ff:ff:ff:ff MAC address indicates broadcasting
packet = ether/arp
# Stacking
result = srp(packet, timeout=5, verbose=3)[0]
# Defining result with timeout parameter
clients= []
# Client list to be finished below
for sent, received in result:
clients.append({'ip': received.psrc, 'mac': received.hwsrc})
# For each response, append ip and mac address to 'clients' list
print("~"*20)
print("-"*20)
print("Devices On This Network:")
print("-"*20)
print("Device" + " " * 4 + "IP Address")
#Text formatting
for client in clients:
if client['mac'].startswith(mac_key):
devsub(client['mac'])
#Running primary filter to only include MAC addresses that pass
# .startswith(mac_key) into devsub function to print device name
# Associated with MAC[9:11] variables, and the appropriate IP address
So this is the current output, with 1 matching device
Upvotes: 1
Views: 1418
Reputation: 3186
It makes more sense to use scapy builtins than rewrite them. In this case, use arping
. To save yourself time as you work with scapy (like here), you should read the manual.
This will print the 4th octets to a file:
from scapy.all import arping
local_devices = arping("192.168.1.0/24")
local_macs = [device[1].src for device in local_devices[0]]
fourth_octets = [mac[9:11] for mac in local_macs]
with open("fourth_octets.txt", "w") as f:
f.write("\n".join(fourth_octet))
>>> # Get local devices. Four have been found, and 252 provided no answer.
>>> local_devices = arping("192.168.128.0/24")
>>> local_devices
(<ARPing: TCP:0 UDP:0 ICMP:0 Other:4>,
<Unanswered: TCP:0 UDP:0 ICMP:0 Other:252>)
>>> # Get the mac addrs of each of the ARP responses with a list comprehension
>>> local_macs = [device[1].src for device in local_devices[0]]
>>> local_macs
['e0:55:3d:4d:e4:58',
'00:18:0a:27:26:ee',
'e0:55:3d:d2:0a:12',
'38:53:9c:08:b9:9f']
>>> # Get the fourth octet by string position in the macs
>>> fourth_octets = [mac[9:11] for mac in local_macs]
>>> fourth_octets
['4d', '27', 'd2', '08']
>>> # Write to the file with the fourth octets, each on a line
>>> with open("fourth_octets.txt", "w") as f:
f.write("\n".join(fourth_octets))
>>> # Verify that the text file looks as expected
>>> with open("fourth_octets.txt") as f:
print(f.read())
4d
27
d2
08
Upvotes: 1