Skip to content

utilities script.py

Ondrej Holecek edited this page Oct 22, 2018 · 32 revisions

Summary

This utility executes custom commands as defined in provided XML file.

The XML file can contain simple or more complex commands, it can conditionally execute some parts based on remote FortiOS version, run internal parses and use their results, save and operated based on user define parameters, etc.

This utility also has a simple GUI interface called scriptgui.py and located in auxi folder.

The output file can be either analysed programatically or it can be converted to easily readable SSH session-like output with script_to_plain.py auxiliary program. When passing the outputs to support, always use the original compressed file.

Usage

Besides the standard command line parameters that most utilities share, following local commands are recognized:

Action parameters - exactly one of these must be specified:

  • --list Checks what cycle names are available in the file referenced by --script option and shown a simple description as specified within the file.

  • --cycle Runs the cycle specified by its name. This option can be used multiple times to run more different cycles (sequentially). If --cycle-time option is also used (see bellow), this time is counted for all cycles together.

Mandatory parameters:

  • --script Path to the XML script to process. If the path is simple filesystem path, that file is loaded directly. It can also be a URL, in which case this is first downloaded and then executed in the same way as if it was a local file.

    Example of a local file can be "/home/user/myscript.xml" for Linux-based systems or "c:\users\user\desktop\myscript.xml" when running on Windows.

    For URLs, at least HTTP and HTTPs protocols are supported (HTTPs is strongly recommended due to sensitive nature of the script - the commands are not restricted anyhow). There are some URL that are usable by anybody:

Not-so-optional parameters:

  • --output If used, the output of each command is appended to the specified file. The format of the file is "JSON Line". See the "Output file" section for detailed format description.

    This option should be used most of the time when you plan to analyse the commands output later (like when sending the output file to the support).

Optional parameters:

  • --compress By default the --output file is compressed using bzip2 algorithm. This option specifies the number of outputs to be buffered before they are compressed and written to the output file. By default it is saved every 10 outputs and the resulting file is about 20 % of the uncompressed file. To disable compression completely use 0.

    If the program is terminated nicely (using CTRL+c, also on Windows - closing the window does not work correctly), the latest buffer is also saved. However, if the program crashes for some reason, the unsaved data is lost, so set the number reasonably.

  • --cycle-time Minimal time (in seconds) one big cycle can run. If the cycle finished before this time, the next cycle will be delayed until the rest of the --cycle-time passes. If the last cycle took more time than this minimum, the next cycle is started immediately.

  • --profile Specifies the profile name to use. Each profile must be defined inside the XML file. Each cycle definition has the default profile name for the cycle, but this option can be used force different profile.

    Profile contains the "administrative" parameters for the cycle, like the delay between subsequent commands.

  • --param The command definition can use some parameters. Some are defined automatically when the script is running, but it is possible to also specify the parameters manually. This option can be specified multiple times to set different parameters.

    It can be useful for example when the script focuses on specific network interface, but it is unknown which interface it should be when the script is being written.

    Following formats are recognized:

    • s:name:value Parameter called "name" will have the simple string "value". Example: "s:test:value".
    • l:name:delimiter:value1,value2,... Parameter called "name" will be a list of strings. The delimiter is used to control how to split the values. For example "l:test:,:v1,v2,v3" means that the parameter "test" will contain values "v1", "v2" and "v3".
  • --quiet By default (without using this option) the output of each command is written to the standard program output. This is mainly to see the progress of the script and it is not meant for saving the output (see --output option). If --quiet is specified, output of the commands will not be shown and only debug and error messages will be printed on the console.

Security

Security is extremely important when dealing with this utility, because there is no restriction of what the commands in XML script file can do.

For the XML script files on your local disk it is up to you to verify their contents or trust the source you got the file from.

However, for the XML files referenced by the URL, this might not be safe enough. Hence by default all the URL files must be digitally signed and the signature must match the public key specified by --public-key command line option. If there is a problem with the signature, the file is refused.

There is one public key distributed with this project (in pubkeys/default.pem) and it is used automatically if no --public-key option is used. All the URL XML scripts officially distributed by this project are signed with the corresponding private key and you will have no problems running them.

If you really don't care about the security of your FortiGate and you are prepared to deal with consequences, there is an option --ignore-signature that will disable this check. Consider yourself warned!

To learn more about how the signature is verified and how to sign your own XML script files, check the sign.py wiki page.

Output file

The output is always appended (ie. it is never automatically truncated). The format is "JSON Lines", meaning that each command output is a separate JSON structure on its own line.

Line for each command executed

The structure contains a hash array with following elements:

  • command Full command that was executed (including inline replacements and parameters).

  • context The context in which the command was executed, can be:

    • null when executed in global context
    • "" (empty) when executed in management VDOM
    • "vdom name" when executed in a specific VDOM
  • output Output of the command. If the command was a simple FortiOS command, this is the text output received on terminal.

    If the internal parser was called, the output is a JSON structure containing the data as received from the parser. Parsers are used to run one or more commands on the background and calculate some parser-specific results (for example extract multiple similar parts of the command output and prepare some kind of summary).

  • time Time when the command was executed.

    This can either be time on the FortiGate device (default) or the local time on the computer running the script (see --time-source option shared by most of the utilities). The time format can also vary as specified by the shared option --time-format (by default it is human readable timestamp with the UTC offset).

  • parameters Hash array of the parameters at the time the command was executed. Be aware that only parameters with name starting with > character are saved (without the > character).

    The main reason for this element is to save some specific device state when the command was executed. For example when some command output depends on previously executed commands. The parameter usually has to be set manually in the XML script and its meaning is not standardised.

  • connected_on Unix timestamp on the local computer when the connection to the FortiGate was established.

  • nonce Random number generated when the connection to the FortiGate is established.

  • info Hash array containing the information about the type of the element that was used to execute the command. It has at least type entry, and depending on its value, other entries might be present:

    • simple Element <simple> was used. No other entries in the hash are saved.
    • continuous Element <continuous> was used. There should be also continuous_index starting at 0 and increasing with each continuous output of the same command.
    • parser Element <parser> was used. There should also be parser_name and parser_input to show what were the input parameters for the parser.
    • automatic The command was run internally by the system to retrieve some necessary information.

First line after successful connection

After each successful connection to the FortiGate, couple of commands are executed to retrieve information about the current state (get system status, get system performance status, and uptime). This is not printed to standard output.

Special record in the same format of standard record is created to the output file. The command field is null and parameter automatic is true.

In the output field, the structure is saved with following entries:

  • internal_commands The array of the outputs from commands mentioned above (in the format of standard entry described above).
  • flags Used to describe operation parameters of the script. Currently following flags are saved:
    • time_source Value of --time-source option used when the script was started.
    • time_format Value of --time-format option used when the script was started.
    • filename Script file or URL specified on the command line.
    • real_filename Script final URL after all redirections.
    • version FortiDebug application version used to collect this output.
  • info Information about the FortiGate, besides some operational fields, following are saved:
    • hostname Hostname as configured on the device.
    • vdoms_enabled True if user VDOMs are enabled on the device.
    • mgmt_vdom Name of the management VDOM.
    • device Full human readable FortiGate model name.
    • serial Serial number of the device.
    • connected_on Unix timestamp when the SSH session was established.
    • nonce Random number generated when the SSH sessions is established.
    • version Hash containing following elements:
      • major FortiOS major version
      • minor FortiOS minor version
      • patch FortiOS patch number
      • build FortiOS build number
      • compilation FortiOS compilation number

The same nonce and connected_on fields are saved in every structure of the standard command output and can be used to match with this special information structure.

XML script file format

Generic structure

The top level element must be <fortidebug_scriptfile> with mandatory version attribute. In order to be able to execute the script, the FortiDebug system must be of the same version or newer. The FortiDebug version is saved in VERSION.txt file in its root directory and it is increased every time a new feature is implemented.

Optional blocks

  • <profiles> Specifies a list of profiles that can be either associated with each cycle in its definition, or overridden by the command line option. Profiles control the operational parameters of the cycle.

    There is the built-in "default" profile that is used in case the cycle specifies no profile name or the profile it specified does not exist.

    Following are the options currently configurable:

    • <intercommand_sleep> Delay in seconds (can be decimal number) between subsequent commands. This is implemented to prevent overloading the FortiGate with too much commands. The default value is 0.5 seconds.

    Example of custom profile called "myprofile" with reduced delay:

    <profiles>
       <profile name="mmyprofile">
          <intercommand_sleep>0.1</intercommand_sleep>
       </profile>
    </profiles>
    
  • <plists> Parameter list name can be specified by each cycle. This is a space where the runtime parameters are stored during the cycle lifetime, but there can be also some parameters prepared before the cycle is started. This can be done either by defining it inside this parameter list element or by command line option. Command line option overwrites the parameters specified in the XML file.

    This can be used for example when writing XML scripts to troubleshoot one network interface when the interface name is unknown in advance. In that case, the parameter such as "iface" can be defined and used in the cycle instead of the real interface name (as ${iface}). The person running the script then uses the --param command line option to select the right interface name.

    Example with "iface" parameter and default value "port3":

    <plists>
       <parameters name="main">
          <param name="iface" value="port3"/>
       </parameters>
    </plists>
    

    In the cycle the command can look like following. Any occurrence of ${param} will be replaced by the value of the parameter:

    <simple> diagnose hardware deviceinfo nic ${iface} </simple>
    

    And to overwrite it on command line use --param s:iface:port5 option.

Mandatory blocks

  • <cycles> Contains definitions of the commands to be executed on the device (aka "cycle").

    Each cycle is specified in its own <cycle> child element with at least the "name" attribute. Following attributes are recognized:

    • name Name of the cycle. Mandatory. Used on command line to start the right cycle.
    • desc Description of the cycle. Is is printed when user runs the utility with --list option.
    • profile Profile name to apply when running the cycle. Can be overridden on command line with --profile option. If not specified, built-in "default" is used.
    • parameters Parameter list name to apply when running the cycle. If not specified, empty list is created.

    Child elements of the <cycle> element control the flow of the script and the commands to be executed.

    Example of a cycle called "mycycle" with profile and parameter list, running just one simple command:

    <cycles>
       <cycle name="mycycle" desc="Documentation example cycle" profile="main" parameters="main">
          <simple> get system performance status </simple>
       </cycle>
    </cycles>
    
    

Cycle command elements

Please see the dedicated wiki page for cycle command elements.

Example

Following example uses the sample script, that runs get sys stat, get sys perf stat, diagnose firewall packet distribution and diagnose snmp ip frags.

Simple XML script

<fortidebug_scriptfile version="1">
   <cycles>
      <cycle name="test" desc="Very simple testing cycle.">
         <echo>This is a simple testing cycle.</echo>

         <simple context="global"   >get system status                    </simple>
         <simple context="global"   >get system performance status        </simple>
         <simple context="mgmt_vdom">diagnose firewall packet distribution</simple>
         <simple context="mgmt_vdom">diagnose snmp ip frags               </simple>
      </cycle>
   </cycles>
</fortidebug_scriptfile>

Script execution

List available cycles

$ ./script.py --host 10.0.0.1 --script ../samples/simplest.xml --list
test                 : Very simple testing cycle.

Execute one cycle

$ ./script.py --host 10.109.16.179 --script ../samples/simplest.xml --cycle test
[2018-09-13 20:03:14+02:00] (script) >>> This is a simple testing cycle.
[2018-09-13 20:03:14+02:00] (script) <<< get system status
[2018-09-13 20:03:14+02:00] (script) Version: FortiGate-1500D v5.6.0,build3404,180828 (GA)
[2018-09-13 20:03:14+02:00] (script) Virus-DB: 62.00176(2018-09-13 07:28)
[2018-09-13 20:03:14+02:00] (script) Extended DB: 1.00000(2012-10-17 15:46)
[...]
[2018-09-13 20:03:15+02:00] (script) <<< get system performance status
[2018-09-13 20:03:15+02:00] (script) CPU states: 0% user 1% system 0% nice 99% idle 0% iowait 0% irq 0% softirq
[2018-09-13 20:03:15+02:00] (script) CPU0 states: 0% user 1% system 0% nice 99% idle 0% iowait 0% irq 0% softirq
[2018-09-13 20:03:15+02:00] (script) CPU1 states: 0% user 0% system 0% nice 100% idle 0% iowait 0% irq 0% softirq
[...]
[2018-09-13 20:03:16+02:00] (script) <<< diagnose firewall packet distribution
[2018-09-13 20:03:16+02:00] (script) getting packet distribution statistics...
[2018-09-13 20:03:16+02:00] (script) 0 bytes - 63 bytes: 7491100 packets
[2018-09-13 20:03:16+02:00] (script) 64 bytes - 127 bytes: 1406786 packets
[...]
[2018-09-13 20:03:17+02:00] (script) <<< diagnose snmp ip frags
[2018-09-13 20:03:17+02:00] (script) ReasmTimeout = 0
[2018-09-13 20:03:17+02:00] (script) ReasmReqds   = 0
[...]
[2018-09-13 20:03:44+02:00] (script) >>> This is a simple testing cycle.
[2018-09-13 20:03:44+02:00] (script) <<< get system status
[2018-09-13 20:03:44+02:00] (script) Version: FortiGate-1500D v5.6.0,build3404,180828 (GA)
[2018-09-13 20:03:44+02:00] (script) Virus-DB: 62.00176(2018-09-13 07:28)
[...]
[2018-09-13 20:03:45+02:00] (script) <<< get system performance status
[2018-09-13 20:03:45+02:00] (script) CPU states: 0% user 1% system 0% nice 99% idle 0% iowait 0% irq 0% softirq
[2018-09-13 20:03:45+02:00] (script) CPU0 states: 0% user 3% system 0% nice 97% idle 0% iowait 0% irq 0% softirq
[...]
[2018-09-13 20:03:46+02:00] (script) <<< diagnose firewall packet distribution
[2018-09-13 20:03:46+02:00] (script) getting packet distribution statistics...
[2018-09-13 20:03:46+02:00] (script) 0 bytes - 63 bytes: 7491360 packets
[2018-09-13 20:03:46+02:00] (script) 64 bytes - 127 bytes: 1406872 packets
[...]
[2018-09-13 20:03:47+02:00] (script) <<< diagnose snmp ip frags
[2018-09-13 20:03:47+02:00] (script) ReasmTimeout = 0
[2018-09-13 20:03:47+02:00] (script) ReasmReqds   = 0
[...]

FAQ

  1. How do I know what commands will be executed on my device?

    You can open the script file in your favourite XML editor (built-in XML viewer in Chrome or Firefox will do well). If you got the URL, you can download it first. The syntax is quite self-explanatory and you can refer to XML script file format section if you have any doubts.

  2. How to read the compressed output file on Windows?

    The output file is bzip2 compressed text file with JSON Lines structure. You can install any utility that supports this format to decompress it and then open in a text editor. The one that was tested is https://www.7-zip.org/.

  3. How do I use the internal plotter tool to generate graphs from collected data?

    Until the plotter can recognise this new format, use script_to_plain.py to generate an SSH session-like text output that the plotter can work with.

Clone this wiki locally