Skip to content

Commit 48fdeb9

Browse files
committed
initial commit
1 parent 9bde7cc commit 48fdeb9

File tree

4 files changed

+230
-0
lines changed

4 files changed

+230
-0
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Python-generate_mac
2+
===================
3+
4+
Python class for Generating Ethernet MAC addresses. Can use the wireshark manuf
5+
for specific vendors, and or a random, but assigned address. Will work with
6+
any file formated the same as said file.
7+
8+
Supported functions:
9+
10+
**total_random()** - Procedurely generated MAC address, using random function.
11+
12+
**vid_file_random(_file_)** - uses random line from wireshark's manuf file
13+
14+
**vid_file_vendor(_file, name_)** - specify a vendor name, uses wireshark's manuf file
15+
instead of being completely random
16+
17+
**vid_provided(_vid bytes_)** - specify the VID bytes when calling the function.
18+
Random device bytes will be generated.

generate_mac/__init__.py

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
#!/usr/bin/env python3
2+
3+
import random
4+
import string
5+
6+
class generate_mac():
7+
'''MAC address generation class'''
8+
_valid_char = "0123456789ABCDEF"
9+
_valid_bcast_char = "02468ACE"
10+
_valid_vendors = set()
11+
_vid_table = {
12+
'36':2,
13+
'32':3,
14+
'28':4,
15+
'none':6,
16+
}
17+
def _strip_comments(in_list):
18+
'''Proccesses out comments using # as the comment character'''
19+
file_lines = []
20+
for line in in_list:
21+
line=line.strip()
22+
if not line.startswith("#") and line != "":
23+
file_lines.append(line.split("#")[0])
24+
return(file_lines)
25+
26+
def _read_vid_file(vid_file):
27+
'''Reads a VID file and returns a list nested list of line contents'''
28+
''' Every line is [MAC,Vendor,Comment]'''
29+
out_lines = []
30+
try:
31+
in_file = open(vid_file,"r")
32+
file_lines = in_file.readlines()
33+
in_file.close()
34+
except FileNotFoundError:
35+
raise FileNotFoundError("ERROR: Cannot read VID file " + in_file)
36+
37+
# Sanitize inputs
38+
file_lines = generate_mac._strip_comments(file_lines)
39+
40+
# Generate a list of lines which are split into a list, make a set of
41+
# vendors
42+
for line in file_lines:
43+
line = line.split('\t')
44+
try:
45+
vendor = line[1]
46+
generate_mac._valid_vendors.add(vendor)
47+
except:
48+
continue
49+
out_lines.append(line)
50+
# delete the first line which is 00:00:00, by Xerox. Malformed, and
51+
# unlikely to be in use with modern equipment
52+
del(file_lines[0])
53+
54+
return out_lines
55+
56+
def _get_processed_vid(in_line):
57+
'''Returns a formated tupple with MAC info (prefix,bytes_needed,vendor,description)'''
58+
59+
# Start with the items that don't need transforms
60+
vendor = in_line[1]
61+
try:
62+
description = in_line[2]
63+
except:
64+
description = ""
65+
66+
# prefix or raw VID bytes
67+
prefix = in_line[0].split('/')[0]
68+
suffix = ''
69+
# get the suffix. It is either going to be 36, 28 or none.
70+
try:
71+
suffix = in_line[0].split('/')[1]
72+
except:
73+
suffix = 'none'
74+
75+
bytes_needed = generate_mac._vid_table[suffix]
76+
77+
# Generate the string returned
78+
out_vid = ''
79+
if suffix == 'none':
80+
out_vid = prefix
81+
else:
82+
# Cut down the trailing zeros so random data can be generated in that
83+
# space
84+
prefix_size = ( 12 - bytes_needed ) // 2
85+
prefix = prefix.split(':')
86+
prefix = prefix[0:prefix_size]
87+
prefix = ":".join(prefix)
88+
out_vid = prefix
89+
90+
return prefix,bytes_needed,vendor,description
91+
92+
def _gen_rand_bytes(bytes_needed):
93+
'''Generate X amount of random bytes, seperated by a :'''
94+
out_bytes = []
95+
rand_byte = ""
96+
for i in range(bytes_needed):
97+
rand_byte = random.choice(generate_mac._valid_char) + random.choice(generate_mac._valid_char)
98+
out_bytes.append(rand_byte)
99+
out_bytes = ":".join(out_bytes)
100+
return out_bytes
101+
102+
def _is_byte(test_byte):
103+
'''Tests if a string is a hexdecimal byte, returns True/False'''
104+
test_byte = test_byte.strip(":")
105+
# If a byte does not convert from hex, its not a byte
106+
try:
107+
test_byte = int(test_byte,16)
108+
except:
109+
return False
110+
# If the value is out of range for a single byte, it is not
111+
if 0 < test_byte > 255:
112+
return False
113+
#If we get to the end, its a byte
114+
return True
115+
116+
def total_random():
117+
'''Generates a completely random mac'''
118+
# An odd number in the first Digit is multi-cast and invalid for
119+
# assignment
120+
first_byte = random.choice(generate_mac._valid_char) + random.choice(generate_mac._valid_bcast_char)
121+
122+
# the rest are random hexdecimal values
123+
five_bytes = generate_mac._gen_rand_bytes(5)
124+
out_mac = first_byte + ":" + five_bytes
125+
return out_mac
126+
127+
def vid_file_random(vid_file):
128+
'''Generates a MAC with random vendor bytes read from a the wireshark manuf file'''
129+
file_lines = generate_mac._read_vid_file(vid_file)
130+
131+
# Get a random line from the file
132+
rand_line = file_lines[ random.randrange( len(file_lines) ) ]
133+
# Get the MAC address from the line
134+
rand_line = generate_mac._get_processed_vid(rand_line)
135+
vid_bytes = rand_line[0]
136+
137+
# Now generate the random device bytes
138+
bytes_needed = rand_line[1] //2
139+
dev_bytes = generate_mac._gen_rand_bytes(bytes_needed)
140+
141+
output = vid_bytes + ":" + dev_bytes
142+
return(output)
143+
144+
def vid_file_vendor(vid_file,vendor):
145+
'''Generates a random MAC from a specified vendor name'''
146+
file_lines = generate_mac._read_vid_file(vid_file)
147+
# Get a random VID assigned to Apple Inc
148+
line_vendor = ""
149+
vid_bytes = ""
150+
descrption = ""
151+
rand_line = ""
152+
if vendor not in generate_mac._valid_vendors:
153+
raise KeyError(vendor + " has no associated VID byte in manuf file")
154+
while line_vendor != vendor:
155+
# Get a random line from the file, and then proccess
156+
rand_line = file_lines[ random.randrange( len(file_lines) ) ]
157+
rand_line = generate_mac._get_processed_vid(rand_line)
158+
# Fill in the blanks
159+
vid_bytes = rand_line[0]
160+
bytes_needed = rand_line[1]
161+
line_vendor = rand_line[2]
162+
description = rand_line[3]
163+
164+
# Now generate the random device bytes
165+
bytes_needed = rand_line[1] //2
166+
dev_bytes = generate_mac._gen_rand_bytes(bytes_needed)
167+
168+
output = vid_bytes + ":" + dev_bytes
169+
return output
170+
171+
def vid_provided(vid_bytes):
172+
'''Generates only the Device bytes, given specified VID bytes'''
173+
test_vid = []
174+
i = ""
175+
rand_bytes = ""
176+
output = ""
177+
## Start with error checking
178+
#remove any trailing :
179+
vid_bytes = vid_bytes.rstrip(":")
180+
test_vid = vid_bytes.split(":")
181+
# If there aren't precisely three bytes, its not a VID
182+
if len(test_vid) != 3:
183+
raise ValueError(vid_bytes + ' are not valid VID bytes')
184+
for i in test_vid:
185+
if generate_mac._is_byte(i) == False:
186+
raise ValueError(vid_bytes + ' are not valid VID bytes')
187+
188+
rand_bytes = generate_mac._gen_rand_bytes(3)
189+
output = vid_bytes + ":" + rand_bytes
190+
return output
4.28 KB
Binary file not shown.

setup.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import setuptools
2+
3+
with open("README.md", "r") as fh:
4+
long_description = fh.read()
5+
6+
setuptools.setup(
7+
name="python-generate_mac",
8+
version="1.0.0",
9+
author="GI_Jack",
10+
author_email="GI_Jack@example.com",
11+
description="Library for generating Ethernet MAC addresses",
12+
long_description=long_description,
13+
long_description_content_type="text/markdown",
14+
url="https://github.com/GIJack/python-generate_mac",
15+
packages=setuptools.find_packages(),
16+
classifiers=[
17+
"Programming Language :: Python :: 3",
18+
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
19+
"Operating System :: OS Independent",
20+
],
21+
python_requires='>=3.0',
22+
)

0 commit comments

Comments
 (0)