197 lines
6.3 KiB
Python
Executable file
197 lines
6.3 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# create the enterprises.c file from
|
|
# https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers
|
|
# or an offline copy
|
|
#
|
|
# Copyright 2022 by Moshe Kaplan
|
|
# Based on make-sminmpec.pl by Gerald Combs
|
|
#
|
|
# Wireshark - Network traffic analyzer
|
|
# By Gerald Combs <gerald@wireshark.org>
|
|
# Copyright 2004 Gerald Combs
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
import os
|
|
import argparse
|
|
import re
|
|
import urllib.request
|
|
|
|
|
|
ENTERPRISES_CFILE = os.path.join('epan', 'enterprises.c')
|
|
|
|
ENTERPRISE_NUMBERS_URL = "https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers"
|
|
|
|
DECIMAL_PATTERN = r"^(\d+)"
|
|
# up to three spaces because of formatting errors in the source
|
|
ORGANIZATION_PATTERN = r"^ ?(\S.*)"
|
|
FORMERLY_PATTERN = r" \(((formerly|previously) .*)\)"
|
|
|
|
|
|
LOOKUP_FUNCTION = r"""
|
|
const char* global_enterprises_lookup(uint32_t value)
|
|
{
|
|
if (value > table.max_idx) {
|
|
return NULL;
|
|
}
|
|
else return table.values[value];
|
|
}
|
|
"""
|
|
|
|
DUMP_FUNCTION = r"""
|
|
void global_enterprises_dump(FILE *fp)
|
|
{
|
|
for (size_t idx = 0; idx <= table.max_idx; idx++) {
|
|
if (table.values[idx] != NULL) {
|
|
fprintf(fp, "%zu\t%s\n", idx, table.values[idx]);
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
|
|
# This intermediate format is no longer written to a file - returned as string
|
|
def generate_enterprise_entries(file_content):
|
|
# We only care about the "Decimal" and "Organization",
|
|
# not the contact or email
|
|
org_lines = []
|
|
last_updated = ""
|
|
end_seen = False
|
|
for line in file_content.splitlines():
|
|
decimal_match = re.match(DECIMAL_PATTERN, line)
|
|
if decimal_match:
|
|
decimal = decimal_match.group(0)
|
|
elif re.match(ORGANIZATION_PATTERN, line):
|
|
organization = line.strip()
|
|
if organization.lower() == "unassigned":
|
|
continue
|
|
organization = re.sub(FORMERLY_PATTERN, r"\t# \1", organization)
|
|
org_lines += [decimal + "\t" + organization]
|
|
elif "last updated" in line.lower():
|
|
last_updated = line
|
|
elif "end of document" in line.lower():
|
|
end_seen = True
|
|
|
|
if not end_seen:
|
|
raise Exception('"End of Document" not found. Truncated source file?')
|
|
|
|
last_updated_line = "/* " + last_updated + " */\n\n"
|
|
output = "\n".join(org_lines) + "\n"
|
|
return (output,last_updated_line)
|
|
|
|
class CFile:
|
|
def __init__(self, filename, last_updated_line):
|
|
self.filename = filename
|
|
self.f = open(filename, 'w')
|
|
self.mappings = {}
|
|
self.highest_num = 0
|
|
|
|
# Write file header
|
|
self.f.write('/* ' + os.path.basename(self.filename) + '\n')
|
|
self.f.write(' *\n')
|
|
self.f.write(' * Wireshark - Network traffic analyzer\n')
|
|
self.f.write(' * By Gerald Combs <gerald@wireshark.org>\n')
|
|
self.f.write(' * Copyright 1998 Gerald Combs\n')
|
|
self.f.write(' *\n')
|
|
self.f.write(' * Do not edit - this file is automatically generated\n')
|
|
self.f.write(' * SPDX-License-Identifier: GPL-2.0-or-later\n')
|
|
self.f.write(' */\n\n')
|
|
self.f.write(last_updated_line)
|
|
|
|
# Include header files
|
|
self.f.write('#include "config.h"\n\n')
|
|
self.f.write('#include <stddef.h>\n')
|
|
self.f.write('#include "enterprises.h"\n')
|
|
self.f.write('\n\n')
|
|
|
|
def __del__(self):
|
|
self.f.write('typedef struct\n')
|
|
self.f.write('{\n')
|
|
self.f.write(' uint32_t max_idx;\n')
|
|
self.f.write(' const char* values[' + str(self.highest_num+1) + '];\n')
|
|
self.f.write('} global_enterprises_table_t;\n\n')
|
|
|
|
# Write static table
|
|
self.f.write('static global_enterprises_table_t table =\n')
|
|
self.f.write('{\n')
|
|
# Largest index
|
|
self.f.write(' ' + str(self.highest_num) + ',\n')
|
|
self.f.write(' {\n')
|
|
# Entries (read from dict)
|
|
for n in range(0, self.highest_num+1):
|
|
if n not in self.mappings:
|
|
# There are some gaps, write a NULL entry so can lookup by index
|
|
line = ' NULL'
|
|
else:
|
|
line = ' "' + self.mappings[n] + '"'
|
|
# Add coma.
|
|
if n < self.highest_num:
|
|
line += ','
|
|
# Add number as aligned comment.
|
|
line += ' '*(90-len(line)) + '// ' + str(n)
|
|
|
|
self.f.write(line+'\n')
|
|
|
|
# End of array
|
|
self.f.write(' }\n')
|
|
# End of struct
|
|
self.f.write('};\n')
|
|
print('Re-generated', self.filename)
|
|
|
|
# Lookup function
|
|
self.f.write(LOOKUP_FUNCTION)
|
|
|
|
# Dump function
|
|
self.f.write(DUMP_FUNCTION)
|
|
|
|
# Add an individual mapping to the function
|
|
def addMapping(self, num, name):
|
|
# Handle some escapings
|
|
name = name.replace('\\', '\\\\')
|
|
name = name.replace('"', '""')
|
|
|
|
# Record.
|
|
self.mappings[num] = name
|
|
self.highest_num = num if num>self.highest_num else self.highest_num
|
|
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Create the {} file.".format(ENTERPRISES_CFILE))
|
|
parser.add_argument('--infile')
|
|
parser.add_argument('outfile', nargs='?', default=ENTERPRISES_CFILE)
|
|
parsed_args = parser.parse_args()
|
|
|
|
# Read data from file or webpage
|
|
if parsed_args.infile:
|
|
with open(parsed_args.infile, encoding='utf-8') as fh:
|
|
data = fh.read()
|
|
else:
|
|
with urllib.request.urlopen(ENTERPRISE_NUMBERS_URL) as f:
|
|
if f.status != 200:
|
|
raise Exception("request for " + ENTERPRISE_NUMBERS_URL + " failed with result code " + f.status)
|
|
data = f.read().decode('utf-8')
|
|
|
|
# Find bits we need and generate enterprise entries
|
|
enterprises_content,last_updated_line = generate_enterprise_entries(data)
|
|
|
|
# Now write to a C file the contents (which is faster than parsing the global file at runtime).
|
|
c_file = CFile(parsed_args.outfile, last_updated_line)
|
|
|
|
mapping_re = re.compile(r'^(\d+)\s+(.*)$')
|
|
for line in enterprises_content.splitlines():
|
|
match = mapping_re.match(line)
|
|
if match:
|
|
num, name = match.group(1), match.group(2)
|
|
# Strip any comments and/or trailing whitespace
|
|
idx = name.find('#')
|
|
if idx != -1:
|
|
name = name[0:idx]
|
|
name = name.rstrip()
|
|
# Add
|
|
c_file.addMapping(int(num), name)
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|