Last active
December 10, 2017 03:33
-
-
Save gvanem/1643c946fb2395b6c8a05c3ec8904e13 to your computer and use it in GitHub Desktop.
A script for tcpdump; generates a oui-generated.c from http://standards-oui.ieee.org/oui.txt and http://www.iana.org/assignments/enterprise-numbers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python | |
| # | |
| # Generates a 'oui-generated.c' for tcpdump. | |
| # | |
| from __future__ import print_function | |
| import sys, os, time, re, getopt, codecs | |
| OUI_URL = "http://standards-oui.ieee.org/oui.txt" | |
| ENT_URL = "http://www.iana.org/assignments/enterprise-numbers" | |
| OUI_TXT = 'oui-generated.txt' | |
| OUI_C = 'oui-generated.c' | |
| ENT_NUM = 'enterprise-numbers' | |
| OUI_C_HEAD = r""" | |
| /* | |
| * %s: "Organizationally Unique Identifier" list | |
| * obtained from %s. | |
| * This file was generated by %s at | |
| * %s. | |
| * DO NOT EDIT! | |
| */ | |
| #ifdef HAVE_CONFIG_H | |
| #include "config.h" | |
| #endif | |
| #include <netdissect-stdinc.h> | |
| #include "netdissect.h" | |
| #include "oui.h" | |
| const struct tok oui_values[] = { | |
| """ | |
| SMI_C_HEAD = r""" | |
| const struct tok smi_values[] = { | |
| { SMI_IETF, "IETF (reserved)"}, | |
| """ | |
| OUI_C_BOTTOM = r""" | |
| /* Comparision routine needed by bsearch() routines. | |
| * Don't use unsigned arithmetic. | |
| */ | |
| static int compare (const struct tok *a, const struct tok *b) | |
| { | |
| return ((long)a->v - (long)b->v); | |
| } | |
| typedef int (*CompareFunc) (const void *, const void *); | |
| const char *oui_val_to_name (unsigned oui) | |
| { | |
| size_t num = sizeof(oui_values) / sizeof(oui_values[0]) - 1; | |
| const struct tok *t = bsearch (&oui, oui_values, num, sizeof(oui_values[0]), | |
| (CompareFunc)compare); | |
| return (t ? t->s : "Unknown"); | |
| } | |
| const char *smi_val_to_name (unsigned smi) | |
| { | |
| size_t num = sizeof(smi_values) / sizeof(smi_values[0]) - 1; | |
| const struct tok *t = bsearch (&smi, smi_values, num, sizeof(smi_values[0]), | |
| (CompareFunc)compare); | |
| return (t ? t->s : "Unknown"); | |
| } | |
| """ | |
| prefixes = dict() | |
| enterprises = dict() | |
| def write_oui_c(): | |
| f = codecs.open (OUI_C, 'w+b', 'UTF-8') | |
| f.write (OUI_C_HEAD % (OUI_C, OUI_URL, __file__, time.ctime())) | |
| for p in sorted(prefixes): | |
| f.write (" { 0x%.2s%.2s%.2s, \"%s\" },\n" % (p[0:], p[3:], p[6:], prefixes[p])) | |
| f.write (" { 0xFFFFFF, NULL } /* Since XEROX CORPORATION has value 0, use this */\n };\n") | |
| f.close() | |
| print ("Wrote %d OUI records to %s" % (len(prefixes), OUI_C)) | |
| def append_oui_c(): | |
| f = codecs.open (OUI_C, 'a+b', 'UTF-8') | |
| f.write (SMI_C_HEAD) | |
| for e in sorted(enterprises): | |
| width = len("SMI_IETF") - len(str(e)) | |
| f.write (" { %d,%*s \"%s\" },\n" % (e, width, "", enterprises[e])) | |
| f.write (" { 0, NULL }\n};\n") | |
| f.write (OUI_C_BOTTOM) | |
| f.close() | |
| print ("Appended %d SMI records to %s" % (len(enterprises), OUI_C)) | |
| # | |
| # The progress callback for 'urllib.urlretrieve()'. | |
| # | |
| def url_progress (blocks, block_size, total_size): | |
| if blocks: | |
| percent = 100 * (blocks*block_size)/total_size | |
| print ("Got %d kBytes (%u%%)\r" % ((block_size*blocks)/1024, percent), end="") | |
| # | |
| # Parse the lines from the download 'oui-generated.txt' file. | |
| # Extract only the first line from each record. | |
| # Grow the 'prefixes[]' dictionary as we walk the list of 'lines'. | |
| # | |
| def parse_oui_txt (lines): | |
| # | |
| # The format of the oui-generated.txt looks like: | |
| # | |
| # OUI/MA-L Organization | |
| # company_id Organization | |
| # Address | |
| # | |
| # E0-43-DB (hex) Shenzhen ViewAt Technology Co.,Ltd. | |
| # E043DB (base 16) Shenzhen ViewAt Technology Co.,Ltd. | |
| # 9A,Microprofit,6th Gaoxin South Road, High-Tech Industrial Park, Nanshan, Shenzhen, CHINA. | |
| # shenzhen guangdong 518057 | |
| # CN | |
| # | |
| # We want to parse only "(hex)" lines. | |
| # | |
| for line in lines: | |
| line = line.rstrip() | |
| if not re.match("^[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}[\t ]*\(hex\)[\t ]*", line): | |
| continue | |
| prefix = line [0:8] | |
| vendor = line [line.rindex('(hex)')+5:].lstrip() | |
| prefixes [prefix] = vendor | |
| # | |
| # Parse the lines from the download 'enterprise-numbers' file. | |
| # Grow the 'enterprises[]' dictionary as we walk the list of 'lines'. | |
| # | |
| def parse_ent_txt (lines): | |
| r = re.compile (r"^(\d+)$") | |
| got_number = 0 | |
| for line in lines: | |
| match = r.search(line) | |
| if got_number == 0 and match: | |
| # | |
| # Org 0 ("Reserved") is already in 'smi_values[0]'. | |
| # Expect "Organization" on the next line. | |
| # | |
| got_number = int(match.group(1)) | |
| continue | |
| if got_number: | |
| # | |
| # Convert (", \, and some \x codes to C-compatible strings. | |
| # | |
| org = line.strip() | |
| org = org.replace (r'\\', r"\\") | |
| org = org.replace (r'"', r'\"') | |
| org = org.replace (r'\T', r'\\T') | |
| org = org.replace (r'\C', r'\\C') | |
| org = org.replace (r'\D', r'\\D') | |
| enterprises [got_number] = org | |
| got_number = 0 | |
| # | |
| # Check if a local 'fname' exist. Otherwise download it from 'url'. | |
| # Return the contents as a list. | |
| # | |
| def get_local_file_or_download (fname, url): | |
| if os.path.exists(fname): | |
| print ("A local %s already exist." % fname) | |
| else: | |
| try: | |
| from urllib import urlretrieve as url_get | |
| except ImportError: | |
| from urllib.request import urlretrieve as url_get | |
| print ("Downloading %s from %s" % (fname, url)) | |
| url_get (url, filename=fname, reporthook=url_progress) | |
| print ("") | |
| # | |
| # Now read 'fname' and return it as a list. | |
| # | |
| data = codecs.open (fname, 'rb', 'UTF-8') | |
| lines = data.read().splitlines() | |
| data.close() | |
| return lines | |
| def usage (err=""): | |
| print ("%s%s [-h | --help]:" % (err, os.path.realpath(sys.argv[0]))) | |
| print (r""" | |
| This script does 2 things: | |
| Creates a %s file from a local %s file | |
| or from one downloaded from here: | |
| %s""" % (OUI_C, OUI_TXT, OUI_URL)) | |
| print (r""" | |
| and: | |
| appends an 'smi_values[]' array at the end of %s. | |
| This is taken from a local %s or from one downloaded from here: | |
| %s""" % (OUI_C, ENT_NUM, ENT_URL)) | |
| sys.exit (0) | |
| ## __main__ | |
| try: | |
| opts, args = getopt.getopt (sys.argv[1:], "?h", ["help"]) | |
| except getopt.GetoptError as e: | |
| usage (e.msg + "\n") | |
| for o, a in opts: | |
| if o in ["-h", "-?", "--help"]: | |
| usage() | |
| l = get_local_file_or_download (OUI_TXT, OUI_URL) | |
| parse_oui_txt (l) | |
| write_oui_c() | |
| l = get_local_file_or_download (ENT_NUM, ENT_URL) | |
| parse_ent_txt (l) | |
| append_oui_c() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment