Skip to content

Instantly share code, notes, and snippets.

@dhondta
Last active August 4, 2023 13:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dhondta/54238677f1979c137a90a6da351f9337 to your computer and use it in GitHub Desktop.
Save dhondta/54238677f1979c137a90a6da351f9337 to your computer and use it in GitHub Desktop.
OUI/MAC Organization Finder

OUI/MAC Organization Finder

This is a small tool using Tinyscript for finding the organization associated with a given OUI or MAC address.

$ pip install tinyscript
$ tsm install oui
#!/usr/bin/python3
from tinyscript import *
from tinyscript.helpers import Path, TempPath
__script__ = "OUI/MAC Organization Finder"
__author__ = "Alexandre D'Hondt"
__email__ = "alexandre.dhondt@gmail.com"
__version__ = "1.1"
__copyright__ = ("A. D'Hondt", 2021)
__license__ = "gpl-3.0"
__doc__ = """
This tool returns the organization name associated to an input OUI or MAC address.
"""
__examples__ = ["50:e0:85:01:23:45", "9C-3E-53-01-23-45 -u"]
PATH_OUI_DB = Path(__file__).dirname.joinpath("oui.tsv")
PATH_XTRA_OUI_DB = Path(__file__).dirname.joinpath("oui-extra.tsv")
TEMP_OUI_DB = TempPath().tempfile()
URL_OUI_DB = "https://standards-oui.ieee.org/"
def add_extra_oui(entry):
new_oui, new_org = list(map(lambda x: x.strip(), entry.split("=", 1)))
with PATH_XTRA_OUI_DB.open('a+') as f:
f.seek(0)
for l in f:
oui, org = l.strip().split("\t", 1)
if new_oui == oui:
logger.warning("OUI '%s' already exists (%s)" % (oui, org))
return
f.write("%s\t%s" % (new_oui, new_org))
logger.info("OUI '%s' added (%s)" % (new_oui, new_org))
def eui_or_oui(oui):
if re.match("(?i)[0-9a-f]{2}([-:]?)[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", oui) or \
re.match("(?i)[0-9a-f]{2}([-:]?)[0-9a-f]{2}(\\1[0-9a-f]{2})$", oui):
org = open_db().get(re.sub(r"[-:]", "", oui.upper()))
if org:
print(org)
else:
logger.failure("OUI not found")
return
raise ValueError("Not an OUI or MAC address")
def open_db():
if not PATH_OUI_DB.exists():
update_db(True)
logger.debug("Opening OUI database...")
db = {}
with PATH_OUI_DB.open('rt') as f:
for l in f:
oui, org = l.split("\t", 1)
db[oui] = org.rstrip("\n")
if PATH_XTRA_OUI_DB.exists():
with PATH_XTRA_OUI_DB.open('rt') as f:
for l in f:
if l.strip().startswith("#") or l.strip() == "":
continue
oui, org = l.split("\t", 1)
db[oui] = org.rstrip("\n")
return db
def search_ouis(pattern):
ouis = []
for oui, org in open_db().items():
if re.search(pattern, org, re.I):
ouis.append((oui, org))
for oui in sorted(ouis):
print("%s\t%s" % oui)
def update_db(new=False):
logger.debug("%s OUI database..." % ["Updating", "Downloading"][new])
data = ""
with requests.get(URL_OUI_DB, stream=True) as resp:
resp.raise_for_status()
with TEMP_OUI_DB.open('wb') as f:
for chunk in resp.iter_content(chunk_size=8192):
f.write(chunk)
with TEMP_OUI_DB.open('rt') as f:
for l in f:
l = l.strip()
m = re.match(r"([0-9A-F]{6})\s+\(base 16\)\t+(.*)$", l)
if m:
data += "%s\t%s\n" % (m.group(1), m.group(2))
with PATH_OUI_DB.open('wt') as f:
f.write(data.rstrip("\n"))
if __name__ == '__main__':
parser.add_argument("oui", nargs="?", type=eui_or_oui, help="OUI or complete MAC address")
parser.add_argument("-a", "--add", type=add_extra_oui, help="add a custom OUI with its organization name",
note="format is \"XXXXXX=orgname\" (with XXXXXX the OUI without separator)")
parser.add_argument("-s", "--search", type=search_ouis, help="search for OUIs given a pattern of organization")
parser.add_argument("-u", "--update", action="store_true", help="update the OUI database",
note="DB source is %s" % URL_OUI_DB)
initialize(noargs_action="usage")
if args.update:
update_db()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment