diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/README.extcap | 189 | ||||
-rwxr-xr-x | doc/extcap_example.py | 175 |
2 files changed, 351 insertions, 13 deletions
diff --git a/doc/README.extcap b/doc/README.extcap index 94ca73584b..50db8f67a3 100644 --- a/doc/README.extcap +++ b/doc/README.extcap @@ -196,6 +196,195 @@ such a check is the same as for Qt RegExp classes. This feature is only active i Qt version of Wireshark. +TOOLBAR CONTROLS +================ +An extcap utility can provide configuration for controls to use in an interface toolbar. +This controls are bidirectional and can be used to control the extcap utility while +capturing. + +This is useful in scenarios where configuration can be done based on findings in the +capture process, setting temporary values or give other inputs without restarting the +current capture. + +Example: + +$ extcapbin --extcap-interfaces +extcap {version=1.0}{display=Example extcap interface} +interface {value=example1}{display=Example interface 1 for extcap} +interface {value=example2}{display=Example interface 2 for extcap} +control {number=0}{type=string}{display=Message}{tooltip=Package message content. Must start with a capital letter.}{validation=[A-Z]+}{required=true} +control {number=1}{type=selector}{display=Time delay}{tooltip=Time delay between packages} +control {number=2}{type=boolean}{display=Verify}{default=true}{tooltip=Verify package content} +control {number=3}{type=button}{display=Turn on}{tooltip=Turn on or off} +control {number=4}{type=button}{role=logger}{display=Log}{tooltip=Show capture log} +value {control=1}{value=1}{display=1 sec} +value {control=1}{value=2}{display=2 sec}{default=true} + +All controls will be presented as GUI elements in a toolbar specific to the extcap +utility. The extcap must not rely on using those controls (they are optional) because +of other capturing tools not using GUI (e.g. tshark, tfshark). + + +CONTROLS +======== +The controls are similar to the ARGUMENTS, but without the CALL element. All controls +may be given a default value at startup and most can be changed during capture, both +by the extcap and the user (depending on the type of control). + +All controls must provide a NUMBER, by which they are identified. No NUMBER may be +provided twice. Also all options must present the elements TYPE and DISPLAY, where +TYPE provides the type of control to add to the toolbar and DISPLAY the name in the GUI. + +Additionally TOOLTIP and PLACEHOLDER may be provided, which will give the user an +explanation within the GUI. + +All controls, except from the logger, help and reset buttons, may be disabled +(and enabled) in GUI by the extcap during capture. This can be because of set-once +operations, or operations which takes some time to complete. + +All control values which are changed by the user (not equal to the default value) will +be sent to the extcap utility when starting a capture. The extcap utility may choose +to discard initial values and set new values, depending on implementation. + +This TYPEs are defined as controls: + + * BOOLEAN - This provides a checkbox with the possibility to set a true/false value. + + The extcap utility can set a default value at startup, and can change (set) and receive + value changes while capturing. When starting a capture the GUI will send the value if + different from the default value. + + The payload is one byte with binary value 0 or 1. + + Valid Commands: Set value, Enable, Disable. + + * BUTTON - This provides a button with different ROLEs: + + ** CONTROL - This button will send a signal. + This is the default role if nothing is configured. + + The extcap utility can set the button text at startup, and can change (set) the + button text and receive button press signals while capturing. The button is + disabled and the button text is restored to the default text when not capturing. + + The payload is either the button text or empty (signal). + + Valid Commands: Set value, Enable, Disable. + + ** LOGGER - This provides a logger mechanism where the extcap utility can send log + entries to be presented in a log window. This communication is unidirectional. + + The payload is the log entry, and should be ended with a newline. + Maximum length is 65535 bytes. + + Valid Commands: Set log entry, Add log entry. + + The Set command will clear the log before adding the entry. + + ** HELP - This button opens the help page, if configured. + This type has no controls and will not be used in communication. + + Valid Commands: NONE. + + ** RESET - This button will restore all control values to default. + This type has no controls and will not be used in communication. + + Valid Commands: NONE. + + * SELECTOR - This provides a combo box with fixed values which can be selected. + + The extcap utility can set default values at startup, and add and remove values and + receive change in value selection while capturing. When starting a capture the GUI + will send the value if different from the default value. + + The payload is a string with the value, and optionally a string with a display + value if this is different from the value. This two string values are separated + by a null character. + + Valid Commands: Set selected value, Add value, Remove value, Enable, Disable. + + If value is empty the Remove command will remove all entries. + + * STRING - This provides a text edit line with the possibility to set a string or any + value which can be represented in a string (integer, float, date, etc.). + + The extcap utility can set a default string value at startup, and can change (set) and + receive value changes while capturing. When starting a capture the GUI will send the + value if different from the default value. + + The payload is a string with the value. Maximum length is 32767 bytes. + + Valid Commands: Set value, Enable, Disable. + + The element VALIDATION allows to provide a regular expression string, which is used + to check the user input for validity beyond normal data type or range checks. + Back-slashes must be escaped (as in \\b for \b). + + +MESSAGES +======== +In addition to the controls it's possible to send a single message from the extcap +utility to the user. This message can be put in the status bar or displayed in a +information, warning or error dialog which must be accepted by the user. This message +does not use the NUMBER argument so this can have any value. + + +CONTROL PROTOCOL +================ +The protocol used to communicate over the control pipes has a fixed size header of +6 bytes and a payload with 0 - 65535 bytes. + +Control packet: + + +----+----+----+----+----+----+----+----+ + | Sync Pipe Indication (1 byte) | + +----+----+----+----+----+----+----+----+ + | Message Length | + | (3 bytes network order) | + +----+----+----+----+----+----+----+----+ + | Control Number (1 byte) | + +----+----+----+----+----+----+----+----+ + | Command (1 byte) | + +----+----+----+----+----+----+----+----+ + | Payload | + | (0 - 65535 bytes) | + +----+----+----+----+----+----+----+----+ + + Sync Pipe Indication: + The common sync pipe indication. This protocol uses the value 'T'. + + Message Length: + Payload length + 2 bytes for argument number and command. + + Control Number: + Unique number to identify the control. This number also gives the order of + the controls in the interface toolbar. + + Command: Control type: + 0 = Initialized none + 1 = Set boolean / button / logger / selector / string + 2 = Add logger / selector + 3 = Remove selector + 4 = Enable boolean / button / selector / string + 5 = Disable boolean / button / selector / string + 6 = Statusbar message none + 7 = Information message none + 8 = Warning message none + 9 = Error message none + + Payload Length: + The length of the following payload. Maximum length is 65535 bytes. + +The Initialized command will be sent from the GUI to the extcap utility when all +initial control values are sent after starting a capture. This is an indication +that the GUI is ready to receive control values. + +The GUI will only send Initialized and Set commands. The extcap utility shall not +send the Initialized command. + +Messages with unknown control number or command will be silently ignored. + + DEVELOPMENT =========== To have extcap support, extcap must be enabled. Moreover the specific extcap must diff --git a/doc/extcap_example.py b/doc/extcap_example.py index 6ab5699afb..e7ea7b2d6b 100755 --- a/doc/extcap_example.py +++ b/doc/extcap_example.py @@ -51,13 +51,38 @@ import struct import binascii from threading import Thread -ERROR_USAGE = 0 -ERROR_ARG = 1 -ERROR_INTERFACE = 2 -ERROR_FIFO = 3 -ERROR_DELAY = 4 - -globalinterface = 0 +ERROR_USAGE = 0 +ERROR_ARG = 1 +ERROR_INTERFACE = 2 +ERROR_FIFO = 3 +ERROR_DELAY = 4 + +CTRL_CMD_INITIALIZED = 0 +CTRL_CMD_SET = 1 +CTRL_CMD_ADD = 2 +CTRL_CMD_REMOVE = 3 +CTRL_CMD_ENABLE = 4 +CTRL_CMD_DISABLE = 5 +CTRL_CMD_STATUSBAR = 6 +CTRL_CMD_INFORMATION = 7 +CTRL_CMD_WARNING = 8 +CTRL_CMD_ERROR = 9 + +CTRL_ARG_MESSAGE = 0 +CTRL_ARG_DELAY = 1 +CTRL_ARG_VERIFY = 2 +CTRL_ARG_BUTTON = 3 +CTRL_ARG_HELP = 4 +CTRL_ARG_RESET = 5 +CTRL_ARG_LOGGER = 6 +CTRL_ARG_NONE = 255 + +initialized = False +message = '' +delay = 0.0 +verify = False +button = False +button_disabled = False """ This code has been taken from http://stackoverflow.com/questions/5943249/python-argparse-and-controlling-overriding-the-exit-status-code - originally developed by Rob Cowie http://stackoverflow.com/users/46690/rob-cowie @@ -128,12 +153,29 @@ def extcap_config(interface): def extcap_interfaces(): - print ("extcap {version=1.0}{help=http://www.wireshark.org}") - print ("interface {value=example1}{display=Example interface usage for extcap}") + print ("extcap {version=1.0}{help=http://www.wireshark.org}{display=Example extcap interface}") + print ("interface {value=example1}{display=Example interface 1 for extcap}") + print ("interface {value=example2}{display=Example interface 2 for extcap}") + print ("control {number=%d}{type=string}{display=Message}{tooltip=Package message content. Must start with a capital letter.}{placeholder=Enter package message content here ...}{validation=^[A-Z]+}" % CTRL_ARG_MESSAGE) + print ("control {number=%d}{type=selector}{display=Time delay}{tooltip=Time delay between packages}" % CTRL_ARG_DELAY) + print ("control {number=%d}{type=boolean}{display=Verify}{default=true}{tooltip=Verify package content}" % CTRL_ARG_VERIFY) + print ("control {number=%d}{type=button}{display=Turn on}{tooltip=Turn on or off}" % CTRL_ARG_BUTTON) + print ("control {number=%d}{type=button}{role=help}{display=Help}{tooltip=Show help}" % CTRL_ARG_HELP) + print ("control {number=%d}{type=button}{role=reset}{display=Reset}{tooltip=Restore default values}" % CTRL_ARG_RESET) + print ("control {number=%d}{type=button}{role=logger}{display=Log}{tooltip=Show capture log}" % CTRL_ARG_LOGGER) + print ("value {control=%d}{value=1}{display=1}" % CTRL_ARG_DELAY) + print ("value {control=%d}{value=2}{display=2}" % CTRL_ARG_DELAY) + print ("value {control=%d}{value=3}{display=3}" % CTRL_ARG_DELAY) + print ("value {control=%d}{value=4}{display=4}" % CTRL_ARG_DELAY) + print ("value {control=%d}{value=5}{display=5}{default=true}" % CTRL_ARG_DELAY) + print ("value {control=%d}{value=60}{display=60}" % CTRL_ARG_DELAY) + def extcap_dlts(interface): if ( interface == '1' ): print ("dlt {number=147}{name=USER0}{display=Demo Implementation for Extcap}") + elif ( interface == '2' ): + print ("dlt {number=148}{name=USER1}{display=Demo Implementation for Extcap}") """ @@ -216,20 +258,125 @@ def pcap_fake_package ( message, fake_ip ): pcap += message return pcap -def extcap_capture(interface, fifo, delay, verify, message, remote, fake_ip): - tdelay = delay if delay != 0 else 5 +def control_read(fn): + try: + header = fn.read(6) + sp, _, length, arg, typ = struct.unpack('>sBHBB', header) + if length > 2: + payload = fn.read(length - 2) + else: + payload = '' + return arg, typ, payload + except: + return None, None, None + +def control_read_thread(control_in, fn_out): + global initialized, message, delay, verify, button, button_disabled + with open(control_in, 'rb', 0 ) as fn: + arg = 0 + while arg != None: + arg, typ, payload = control_read(fn) + log = '' + if typ == CTRL_CMD_INITIALIZED: + initialized = True + elif arg == CTRL_ARG_MESSAGE: + message = payload + log = "Message = " + payload + elif arg == CTRL_ARG_DELAY: + delay = float(payload) + log = "Time delay = " + payload + elif arg == CTRL_ARG_VERIFY: + # Only read this after initialized + if initialized: + verify = (payload[0] != '\0') + log = "Verify = " + str(verify) + control_write(fn_out, CTRL_ARG_NONE, CTRL_CMD_STATUSBAR, "Verify changed") + elif arg == CTRL_ARG_BUTTON: + control_write(fn_out, CTRL_ARG_BUTTON, CTRL_CMD_DISABLE, "") + button_disabled = True + if button == True: + control_write(fn_out, CTRL_ARG_BUTTON, CTRL_CMD_SET, "Turn on") + button = False + log = "Button turned off" + else: + control_write(fn_out, CTRL_ARG_BUTTON, CTRL_CMD_SET, "Turn off") + button = True + log = "Button turned on" + + if len(log) > 0: + control_write(fn_out, CTRL_ARG_LOGGER, CTRL_CMD_ADD, log + "\n") + +def control_write(fn, arg, typ, payload): + packet = bytearray() + packet += struct.pack('>sBHBB', 'T', 0, len(payload) + 2, arg, typ) + packet += payload + fn.write(packet) + +def control_write_defaults(fn_out): + global initialized, message, delay, verify + + while not initialized: + time.sleep(.1) # Wait for initial control values + + # Write startup configuration to Toolbar controls + control_write(fn_out, CTRL_ARG_MESSAGE, CTRL_CMD_SET, message) + control_write(fn_out, CTRL_ARG_DELAY, CTRL_CMD_SET, str(delay)) + control_write(fn_out, CTRL_ARG_VERIFY, CTRL_CMD_SET, struct.pack('B', verify)) + + for i in range(1,16): + item = bytearray() + item += str(i) + struct.pack('B', 0) + str(i) + " sec" + control_write(fn_out, CTRL_ARG_DELAY, CTRL_CMD_ADD, item) + + control_write(fn_out, CTRL_ARG_DELAY, CTRL_CMD_REMOVE, str(60)) + +def extcap_capture(interface, fifo, control_in, control_out, in_delay, in_verify, in_message, remote, fake_ip): + global message, delay, verify, button_disabled + delay = in_delay if in_delay != 0 else 5 + message = in_message + verify = in_verify + counter = 1 if not os.path.exists(fifo): print ( "Fifo does not exist, exiting!", file=sys.stderr ) sys.exit(1) + fn_out = None + if control_out != None: + fn_out = open(control_out, 'wb', 0) + control_write(fn_out, CTRL_ARG_LOGGER, CTRL_CMD_SET, "Log started at " + time.strftime("%c") + "\n") + + + if control_in != None: + # Start reading thread + thread = Thread(target = control_read_thread, args = (control_in, fn_out)) + thread.start() + + + if fn_out != None: + control_write_defaults(fn_out) + with open(fifo, 'wb', 0 ) as fh: fh.write (pcap_fake_header()) while True: + if fn_out != None: + log = "Received packet #" + str(counter) + "\n" + control_write(fn_out, CTRL_ARG_LOGGER, CTRL_CMD_ADD, log) + counter = counter + 1 + + if button_disabled == True: + control_write(fn_out, CTRL_ARG_BUTTON, CTRL_CMD_ENABLE, "") + control_write(fn_out, CTRL_ARG_NONE, CTRL_CMD_INFORMATION, "Turn action finished.") + button_disabled = False + out = ("%s|%04X%s|%s" % ( remote.strip(), len(message), message, verify )).encode("utf8") fh.write (pcap_fake_package(out, fake_ip)) - time.sleep(tdelay) + time.sleep(delay) + + thread.join() + if fn_out != None: + fn_out.close() def extcap_close_fifo(fifo): if not os.path.exists(fifo): @@ -268,6 +415,8 @@ if __name__ == '__main__': parser.add_argument("--extcap-config", help="Provide a list of configurations for the given interface", action="store_true") parser.add_argument("--extcap-capture-filter", help="Used together with capture to provide a capture filter") parser.add_argument("--fifo", help="Use together with capture to provide the fifo to dump data to") + parser.add_argument("--extcap-control-in", help="Use together with capture to provide the fifo to dump data to") + parser.add_argument("--extcap-control-out", help="Use together with capture to provide the fifo to dump data to") # Interface Arguments parser.add_argument("--verify", help="Demonstrates a verification bool flag", action="store_true" ) @@ -334,7 +483,7 @@ if __name__ == '__main__': sys.exit(ERROR_DELAY) try: - extcap_capture(interface, args.fifo, args.delay, args.verify, message, args.remote, fake_ip) + extcap_capture(interface, args.fifo, args.extcap_control_in, args.extcap_control_out, args.delay, args.verify, message, args.remote, fake_ip) except KeyboardInterrupt: pass else: |