LATER... ei_kerberos_kdc_session_key ...
[wireshark-sm.git] / tools / generate-dissector.py
blobaee1d6155867d635f742e7bf75596a7dcfe1e4f1
1 #!/usr/bin/env python3
3 # Copyright 2019, Dario Lombardo <lomato@gmail.com>
5 # Wireshark - Network traffic analyzer
6 # By Gerald Combs <gerald@wireshark.org>
7 # Copyright 1998 Gerald Combs
9 # SPDX-License-Identifier: GPL-2.0-or-later
11 # This script generates a Wireshark skeleton dissector, based on the example in the doc/ directory.
13 # Example usage:
15 # generate-dissector.py --name "My Self" --email "myself@example.com" --protoname "The dumb protocol"
16 # --protoshortname DUMB --protoabbrev dumb --license GPL-2.0-or-later --years "2019-2020"
19 import argparse
20 from datetime import datetime
21 import os
24 parser = argparse.ArgumentParser(description='The Wireshark Dissector Generator')
25 parser.add_argument("--name", help="The author of the dissector", required=True)
26 parser.add_argument("--email", help="The email address of the author", required=True)
27 parser.add_argument("--protoname", help="The name of the protocol", required=True)
28 parser.add_argument("--protoshortname", help="The protocol short name", required=True)
29 parser.add_argument("--protoabbrev", help="The protocol abbreviation", required=True)
30 parser.add_argument("--license", help="The license for this dissector (please use a SPDX-License-Identifier). If omitted, %(default)s will be used", default="GPL-2.0-or-later")
31 parser.add_argument("--years", help="Years of validity for the license. If omitted, the current year will be used", default=str(datetime.now().year))
32 parser.add_argument("-f", "--force", action='store_true', help="Force overwriting the dissector file if it already exists")
33 parser.add_argument("-p", "--plugin", action='store_true', help="Create as a plugin. Default is to create in epan")
36 def wsdir():
37 return os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
40 def output_dir(args):
41 if args.plugin:
42 os.makedirs(os.path.join(wsdir(), "plugins/epan/" + args.protoabbrev), exist_ok=True)
43 return os.path.join(wsdir(), "plugins/epan/" + args.protoabbrev)
44 return os.path.join(wsdir(), "epan/dissectors")
47 def output_file(args):
48 return os.path.join(output_dir(args), "packet-" + args.protoabbrev + ".c")
51 def read_skeleton(filename):
52 skeletonfile = os.path.join(wsdir(), "doc/" + filename)
53 print("Reading skeleton file: " + skeletonfile)
54 return open(skeletonfile).read()
57 def replace_fields(buffer, args):
58 print("Replacing fields in skeleton")
59 output = buffer\
60 .replace("YOUR_NAME", args.name)\
61 .replace("YOUR_EMAIL_ADDRESS", args.email)\
62 .replace("PROTONAME", args.protoname)\
63 .replace("PROTOSHORTNAME", args.protoshortname)\
64 .replace("PROTOABBREV", args.protoabbrev)\
65 .replace("FIELDNAME", "Sample Field")\
66 .replace("FIELDABBREV", "sample_field")\
67 .replace("FT_FIELDTYPE", "FT_STRING")\
68 .replace("FIELDDISPLAY", "BASE_NONE")\
69 .replace("FIELDCONVERT", "NULL")\
70 .replace("BITMASK", "0x0")\
71 .replace("FIELDDESCR", "NULL")\
72 .replace("MAX_NEEDED_FOR_HEURISTICS", "1")\
73 .replace("TEST_HEURISTICS_FAIL", "0")\
74 .replace("ENC_xxx", "ENC_NA")\
75 .replace("EXPERTABBREV", "expert")\
76 .replace("PI_GROUP", "PI_PROTOCOL")\
77 .replace("PI_SEVERITY", "PI_ERROR")\
78 .replace("TEST_EXPERT_condition", "0")\
79 .replace("const char *subtree", "\"\"")\
80 .replace("LICENSE", args.license)\
81 .replace("YEARS", args.years)
83 return output
86 def write_dissector(buffer, args):
87 ofile = output_file(args)
88 if os.path.isfile(ofile) and not args.force:
89 raise Exception("The file " + ofile + " already exists. You're likely overwriting an existing dissector.")
90 print("Writing output file: " + ofile)
91 return open(ofile, "w").write(buffer)
94 def patch_makefile(args):
95 if args.plugin:
96 cmakefile = os.path.join(wsdir(), "CMakeLists.txt")
97 patchline = "\t\tplugins/epan/" + args.protoabbrev
98 groupstart = "set(PLUGIN_SRC_DIRS"
99 else:
100 cmakefile = os.path.join(wsdir(), "epan/dissectors/CMakeLists.txt")
101 patchline = "\t${CMAKE_CURRENT_SOURCE_DIR}/packet-" + args.protoabbrev + ".c"
102 groupstart = "set(DISSECTOR_SRC"
103 print("Patching makefile: " + cmakefile)
104 output = ""
105 in_group = False
106 patched = False
107 for line in open(cmakefile):
108 line_strip = line.strip()
109 if in_group and line_strip == ")":
110 in_group = False
111 if in_group and not patched and line_strip > patchline:
112 output += patchline + "\n"
113 patched = True
114 if line_strip == groupstart:
115 in_group = True
116 if line_strip != patchline:
117 output += line
118 open(cmakefile, "w").write(output)
121 def write_plugin_makefile(args):
122 if not args.plugin:
123 return True
124 buffer = replace_fields(read_skeleton("CMakeLists-PROTOABBREV.txt"), args)
125 ofile = os.path.join(output_dir(args), "CMakeLists.txt")
126 print("Writing output file: " + ofile)
127 return open(ofile, "w").write(buffer)
130 def print_header():
131 print("")
132 print("**************************************************")
133 print("* Wireshark skeleton dissector generator *")
134 print("* *")
135 print("* Generate a new dissector for your protocol *")
136 print("* starting from the skeleton provided in the *")
137 print("* doc directory. *")
138 print("* *")
139 print("* Copyright 2019 Dario Lombardo *")
140 print("**************************************************")
141 print("")
144 def print_trailer(args):
145 print("")
146 print("The skeleton for the dissector of the " + args.protoshortname + " protocol has been generated.")
147 print("Please review/extend it to match your specific criteria.")
148 print("")
151 if __name__ == '__main__':
152 print_header()
153 args = parser.parse_args()
154 buffer = replace_fields(read_skeleton("packet-PROTOABBREV.c"), args)
155 write_dissector(buffer, args)
156 patch_makefile(args)
157 write_plugin_makefile(args)
158 print_trailer(args)