├── .gitignore
├── LICENCE
├── MANIFEST.in
├── README.md
├── examples
├── addvlan.py
├── example.script
└── getproperty.py
├── setup.py
├── stormshield
├── __init__.py
└── sns
│ ├── __init__.py
│ ├── bundle.ca
│ ├── cli.py
│ ├── cmd.complete
│ ├── configparser.py
│ ├── crc.py
│ └── sslclient
│ ├── __init__.py
│ └── __version__.py
├── tests
├── test_auth.py
├── test_cert.py
├── test_configparser.py
├── test_file.py
├── test_format_ini.py
├── test_proxy.py
└── test_utf8.py
└── tox.ini
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 | dist
3 | build
4 | .eggs
5 | stormshield.sns.sslclient.egg-info
6 | __pycache__
7 | *.pyc
8 | .tox
9 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | Copyright 2018 Stormshield
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include stormshield/sns/bundle.ca
2 | include stormshield/sns/cmd.complete
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # python-SNS-API
2 |
3 | A Python client for the Stormshield Network Security appliance SSL API.
4 |
5 | Note: this module requires python3.7 or later.
6 |
7 | ## API usage
8 |
9 | ```python
10 | from stormshield.sns.sslclient import SSLClient
11 |
12 | client = SSLClient(
13 | host="10.0.0.254", port=443,
14 | user='admin', password='password',
15 | sslverifyhost=False)
16 |
17 | response = client.send_command("SYSTEM PROPERTY")
18 |
19 | if response:
20 | model = response.data['Result']['Model']
21 | version = response.data['Result']['Version']
22 |
23 | print("Model: {}".format(model))
24 | print("Firmware version: {}".format(version))
25 | else:
26 | print("Command failed: {}".format(response.output))
27 |
28 | client.disconnect()
29 |
30 | ```
31 |
32 | * **Note:** Starting from the 5.0 firmware, a custom CA is used by default by the SSL API. To continue to connect checking the certificate authority of the appliance, the "SNS-WebServer-default-authority" CA must be retrieved from each appliance, then added to a cabundle.pem file. Alternatively, CA verification can be bypassed using sslverifypeer=False argument to SSLClient().
33 |
34 | ### Command results
35 |
36 | Command results are available in text, xml or python structure formats:
37 |
38 | ```python
39 | >>> response = client.send_command("CONFIG NTP SERVER LIST")
40 |
41 | >>> print(response.output)
42 | 101 code=00a01000 msg="Begin" format="section_line"
43 | [Result]
44 | name=ntp1.stormshieldcs.eu keynum=none type=host
45 | name=ntp2.stormshieldcs.eu keynum=none type=host
46 | 100 code=00a00100 msg="Ok"
47 |
48 | >>> print(response.xml)
49 |
50 |
51 |
52 | >>> print(response.data)
53 | {'Result': [{'name': 'ntp1.stormshieldcs.eu', 'keynum': 'none', 'type': 'host'}, {'name': 'ntp2.stormshieldcs.eu', 'keynum': 'none', 'type': 'host'}]}
54 |
55 | ```
56 |
57 | The keys of the `data` property are case insensitive, `response.data['Result'][0]['name']` and `response.data['ReSuLt'][0]['NaMe']` will return the same value.
58 |
59 | Results token are also available via `response.parser.get()` method which accepts a default parameter to return if the token is not present.
60 |
61 | ```python
62 | >>> print(response.output)
63 | 101 code=00a01000 msg="Begin" format="section"
64 | [Server]
65 | 1=dns1.google.com
66 | 2=dns2.google.com
67 | 100 code=00a00100 msg="Ok"
68 |
69 | >>> print(response.data['Server']['3'])
70 | Traceback (most recent call last):
71 | File "", line 1, in
72 | File "/usr/local/lib/python3.7/site-packages/requests/structures.py", line 52, in __getitem__
73 | return self._store[key.lower()][1]
74 | KeyError: '3'
75 |
76 | >>> print(response.parser.get(section='Server', token='3', default=None))
77 | None
78 |
79 | ```
80 |
81 | ### File upload/download
82 |
83 | Files can be downloaded to or uploaded from the client host by adding a redirection to a file with '>' or '<' at the end of the configuration command.
84 |
85 | ```python
86 | >>> client.send_command("CONFIG BACKUP list=all > /tmp/mybackup.na")
87 | 100 code=00a00100 msg="Ok"
88 | ```
89 |
90 | ## snscli
91 |
92 | `snscli` is a python cli for executing configuration commands and scripts on Stormshield Network Security appliances.
93 |
94 | * Output format can be chosen between section/ini or xml
95 | * File upload and download available with adding `< upload` or `> download` at the end of the command
96 | * Client can execute script files using `--script` option.
97 | * Comments are allowed with `#`
98 |
99 | `$ snscli --host `
100 |
101 | `$ snscli --host --user admin --password admin --script config.script`
102 |
103 | Concerning the SSL validation:
104 |
105 | * For the first connection to a new appliance, ssl host name verification can be bypassed with `--no-sslverifyhost` option.
106 | * To connect to a known appliance with the default certificate use `--host --ip ` to validate the peer certificate.
107 | * If a custom CA and certificate is installed, use `--host myfirewall.tld --cabundle `. CA bundle should contain at least the root CA.
108 | * For client certificate authentication, the expected format is a PEM file with the certificate and the unencrypted key concatenated.
109 |
110 | * **Note:** Starting from the 5.0 firmware, a custom CA is used by default by the SSL API. To continue to connect checking the certificate authority of the appliance, the "SNS-WebServer-default-authority" CA must be retrieved from each appliance, then added to a cabundle.pem file. Alternatively, CA verification can be bypassed using `--no-sslverifypeer` option.
111 |
112 | ## Proxy
113 |
114 | The library and `snscli` tool support HTTP and SOCKS proxies, use `--proxy scheme://user:password@host:port` option.
115 |
116 |
117 | ## Build
118 |
119 | `$ python3 setup.py sdist bdist_wheel`
120 |
121 |
122 | ## Install
123 |
124 | ## From PyPI:
125 |
126 | `$ pip3 install stormshield.sns.sslclient`
127 |
128 | ## From source:
129 |
130 | `$ python3 setup.py install`
131 |
132 |
133 | ## Tests
134 |
135 | Warning: some tests require a remote SNS appliance.
136 |
137 | `$ PASSWORD=password APPLIANCE=10.0.0.254 tox`
138 |
139 | To run one test:
140 |
141 | `tox -- tests/test_format_ini`
142 |
143 |
144 | To run `snscli` from the source folder without install:
145 |
146 | `$ PYTHONPATH=. python3 stormshield/sns/cli.py --help`
147 |
148 |
149 | ## Links
150 |
151 | * [Stormshield corporate website](https://www.stormshield.com)
152 | * [CLI commands reference guide](https://documentation.stormshield.eu/SNS/v3/en/Content/CLI_Serverd_Commands_reference_Guide_v3/Introduction.htm)
153 | * [Python SNS API example scripts](https://github.com/stormshield/sns-scripting/tree/master/python)
154 |
--------------------------------------------------------------------------------
/examples/addvlan.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | """
4 | Script to create a VLAN interface on a SNS appliance
5 | """
6 |
7 | import sys
8 | import getpass
9 |
10 | from stormshield.sns.sslclient import SSLClient
11 |
12 | # user input
13 | host = input("Appliance ip address: ")
14 | user = input("User:")
15 | password = getpass.getpass("Password: ")
16 | vlanname = input("VLAN name: ")
17 | vlanphy = input("Physical interface: ")
18 | vlantag = input("VLAN tag: ")
19 | vlanaddr = input("Address: ")
20 | vlanmask = input("Mask: ")
21 |
22 | #host = "10.0.0.0.254"
23 | #user = "admin"
24 | #password = "mypassword"
25 | #vlanname = "myvlan3"
26 | #vlanphy = "Ethernet0"
27 | #vlantag = 103
28 | #vlanaddr = "192.168.103.1"
29 | #vlanmask = "255.255.255.0"
30 |
31 | MAXVLAN=60
32 |
33 | # connect to the appliance
34 | client = SSLClient(
35 | host=host, port=443,
36 | user=user, password=password,
37 | sslverifyhost=False)
38 |
39 | def error(msg):
40 | global client
41 |
42 | print("ERROR: {}".format(msg))
43 | client.disconnect()
44 | sys.exit(1)
45 |
46 | def command(cmd):
47 | global client
48 |
49 | response = client.send_command(cmd)
50 | if not response:
51 | error("command failed:\n{}".format(response.output))
52 |
53 | return response
54 |
55 |
56 | # get vlan list & extract first available vlanX interface
57 | response = command("config network interface show filter=vlan")
58 | if len(response.data.keys()) == 0:
59 | vlanid = 0
60 | else:
61 | vlanid = -1
62 | for i in range(MAXVLAN):
63 | if "vlan{}".format(i) not in response.data:
64 | vlanid = i
65 | break
66 | if vlanid == -1:
67 | error("all available VLAN already created")
68 |
69 |
70 | response = command("CONFIG NETWORK INTERFACE CREATE state=1 protected=0 mtu=1500 physical={} name={} tag={} priority=0 keepVlanPriority=1 maxThroughput=0 ifname=vlan{} address={} mask={}".format(vlanphy, vlanname, vlantag, vlanid, vlanaddr, vlanmask))
71 | if response.code:
72 | print("VLAN vlan{} created".format(vlanid))
73 | else:
74 | error("VLAN vlan{} can't be created:\n{}".format(vlanid, response.output))
75 |
76 | response = command("CONFIG NETWORK ACTIVATE")
77 | if response.code:
78 | print("Configuration activated")
79 | else:
80 | error("Can't activate network:\n{}".format(response.output))
81 |
82 | client.disconnect()
83 |
--------------------------------------------------------------------------------
/examples/example.script:
--------------------------------------------------------------------------------
1 | #system information
2 | SYSTEM PROPERTY
3 |
4 |
--------------------------------------------------------------------------------
/examples/getproperty.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | """
4 | This example show how to connect to a SNS appliance, send a command
5 | to get appliance properties and parse the result to extract the
6 | appliance model and firmware version.
7 | """
8 |
9 | import getpass
10 |
11 | from stormshield.sns.sslclient import SSLClient
12 |
13 | # user input
14 | host = input("Appliance ip address: ")
15 | user = input("User:")
16 | password = getpass.getpass("Password: ")
17 |
18 | # connect to the appliance
19 | client = SSLClient(
20 | host=host, port=443,
21 | user=user, password=password,
22 | sslverifyhost=False)
23 |
24 | # request appliance properties
25 | response = client.send_command("SYSTEM PROPERTY")
26 |
27 | if response:
28 | #get value using parser get method
29 | model = response.parser.get(section='Result', token='Model')
30 | # get value with direct access to data
31 | version = response.data['Result']['Version']
32 |
33 | print("")
34 | print("Model: {}".format(model))
35 | print("Firmware version: {}".format(version))
36 | else:
37 | print("Command failed: {}".format(response.output))
38 |
39 | client.disconnect()
40 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import setuptools
4 | import os
5 |
6 | version = {}
7 | with open(os.path.join('stormshield', 'sns', 'sslclient', '__version__.py'), 'r') as fh:
8 | exec(fh.read(), version)
9 |
10 | with open("README.md", "r") as fh:
11 | long_description = fh.read()
12 |
13 | setuptools.setup(
14 | name="stormshield.sns.sslclient",
15 | version=version['__version__'],
16 | author="Remi Pauchet",
17 | author_email="remi.pauchet@stormshield.eu",
18 | description="SSL API client for Stormshield Network Security appliances",
19 | long_description=long_description,
20 | long_description_content_type="text/markdown",
21 | url="https://github.com/stormshield/python-SNS-API",
22 | license='Apache License 2.0',
23 | packages=setuptools.find_packages(),
24 | entry_points={
25 | 'console_scripts': ['snscli=stormshield.sns.cli:main'],
26 | },
27 | install_requires=[
28 | 'pygments',
29 | 'requests[socks]',
30 | 'requests_toolbelt',
31 | 'colorlog',
32 | 'defusedxml',
33 | 'packaging',
34 | 'pyreadline; platform_system == "Windows"'
35 | ],
36 | include_package_data=True,
37 | tests_require=["pytest"],
38 | classifiers=[
39 | "Programming Language :: Python :: 3",
40 | "Programming Language :: Python :: 3.7",
41 | "License :: OSI Approved :: Apache Software License",
42 | "Operating System :: OS Independent",
43 | "Topic :: System :: Networking",
44 | "Environment :: Console"
45 | ],
46 | )
47 |
--------------------------------------------------------------------------------
/stormshield/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stormshield/python-SNS-API/05b719bfd8a1777f29fa25c385b357f7e56576ef/stormshield/__init__.py
--------------------------------------------------------------------------------
/stormshield/sns/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stormshield/python-SNS-API/05b719bfd8a1777f29fa25c385b357f7e56576ef/stormshield/sns/__init__.py
--------------------------------------------------------------------------------
/stormshield/sns/bundle.ca:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIEFDCCAvygAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmjELMAkGA1UEBhMCRlIx
3 | DTALBgNVBAgTBE5vcmQxGjAYBgNVBAcTEVZpbGxlbmV1dmUgZCdBc2NxMS4wLAYD
4 | VQQKEyVORVRBU1EgLSBTZWN1cmUgSW50ZXJuZXQgQ29ubmVjdGl2aXR5MTAwLgYD
5 | VQQLEydORVRBU1EgRmlyZXdhbGwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN
6 | MDIwNTE0MTIxNTI1WhcNMzgwMTAxMTMxMjU1WjCBmjELMAkGA1UEBhMCRlIxDTAL
7 | BgNVBAgTBE5vcmQxGjAYBgNVBAcTEVZpbGxlbmV1dmUgZCdBc2NxMS4wLAYDVQQK
8 | EyVORVRBU1EgLSBTZWN1cmUgSW50ZXJuZXQgQ29ubmVjdGl2aXR5MTAwLgYDVQQL
9 | EydORVRBU1EgRmlyZXdhbGwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0G
10 | CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaKogZ3NPpoJyFk4JaY6EgyI2t53CN
11 | Xx48WxeNZ3iWuQqQFuFCc1AIZ8bqI4N8T9JoneKv80sMZXvMNOIrYrPae3S4+ecO
12 | nDRtpSj96EdhDxW4aG6Q3JF/TFjMYwmkcxepFUMYe6O+kDFQUEEmWIzNY+kIoxhH
13 | Nd+ySjwPyzkcfspcTrxFRfnZsX/6RcbOWRRJ/HnhgcFZS2SGAFag4P7ULyAaThai
14 | xkFWoT+g2E2suFo6CaMtkxekzNVO9u1ePUgp/uCjZzZ5XvjlvRZg4E7ZHw93noIB
15 | g9VHXj9yKdGUhoN0GnVBD2CPERTgzYUfoQ4jNxbRJEV1LNgbQ9AdwVW7AgMBAAGj
16 | YzBhMB0GA1UdDgQWBBTNdCUgNq+7yVN9mLhW6Q6m3yfubTAfBgNVHSMEGDAWgBTN
17 | dCUgNq+7yVN9mLhW6Q6m3yfubTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
18 | AwIBBjANBgkqhkiG9w0BAQsFAAOCAQEANlzs11N2N1fWTnpD2DI1m6f9/FAkHgZ7
19 | OSberI7M8hIM6ozHrw0OcOSnjoXqrBV/7qjemUki3TpSuiDNxq0Lcfu9rwH+y0hr
20 | DIgxvp8kj9JJsvUjCZLVwY8MTAiBaHEeZ5PFx9KZjKm9iF2MyVuiHdV3BZYmBghM
21 | J7OTjMulwnr/rRfnjuhpwUhcu+bg2gLUYFPFAQv/MlyFHRBk7vOMXphq4U+YEj+m
22 | LK5MP7gayXh6ZKhWWlFzhIb5l9vhjc3P2pgBKI6tuOsDsy3cO46AmNTz4LTd2Jgi
23 | 6Su2L8FWWOI7JTEc97NcW9IE1xHBq/ymLQFlNk2xM0qDyU9PARgG8Q==
24 | -----END CERTIFICATE-----
25 | -----BEGIN CERTIFICATE-----
26 | MIIF/TCCA+WgAwIBAgIJAI5vhN6XX26VMA0GCSqGSIb3DQEBCwUAMIGBMQswCQYD
27 | VQQGEwJGUjEcMBoGA1UEBwwTSXNzeS1MZXMtTW91bGluZWF1eDEUMBIGA1UECgwL
28 | U3Rvcm1zaGllbGQxFzAVBgNVBAsMDkNsb3VkIFNlcnZpY2VzMSUwIwYDVQQDDBxT
29 | dG9ybXNoaWVsZCBQcm9kdWN0cyBSb290IENBMB4XDTE2MDUyNjExMzc1MloXDTM4
30 | MDExMTExMzc1MlowgYExCzAJBgNVBAYTAkZSMRwwGgYDVQQHDBNJc3N5LUxlcy1N
31 | b3VsaW5lYXV4MRQwEgYDVQQKDAtTdG9ybXNoaWVsZDEXMBUGA1UECwwOQ2xvdWQg
32 | U2VydmljZXMxJTAjBgNVBAMMHFN0b3Jtc2hpZWxkIFByb2R1Y3RzIFJvb3QgQ0Ew
33 | ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC87MX9Nwu7Cv9JI0+EcIVU
34 | eWQ5byTXhRhOIKwYbDA4cu9Yv74IYYL0xOuUFDR2i+NO4kbyVL43Rw5114ezIYlb
35 | IbzZDppAZJNEkapRVMWeGhOjPkUJ+dzvIZGBw0+j0KuKRpVMNLT2ej2SMl2/wy8j
36 | 8sEWHb+4dgnVW7izHfianBt3979MQQVAilEw6KOecM9IMJBcjUOURISsemHufdfg
37 | 7U6JlRwwvq00w9GIjf7IzkQLMstVOIG3ZvROp0Ari6EOOxZcTM/19pnoiTjDoK28
38 | bWw2raOxfZ9N4P9nxUCbcyhPWGjj34Q3JOJ82yEPEfgNxOP4p8hAMQ8aWF5wADRx
39 | 6Z6fDwL1GT6MftTNC9h+m1ihZzsI2bzLEria9geQBDRO7yohAgQImutOIBoM8fXF
40 | zEuH9Kr694LzLfCWlmo33eCzSuQXg/YhRYH4h2L9dWqJOaYbfjNeZwQ3dl+nPJIe
41 | LVKp6ERWREppaKwrzLSgT4T+D35M3G8iayNYMC9VeKIKtzbvtADl/IENobgDZeUd
42 | +G3bMZABlXTp36oqPV5Nsv6X9UQExJ0afxe0iZ+FGGQd7Ck4WVdt+Tt65bU6ghbV
43 | JOW947jX9ITPBOBM8nGDrXPxl4wPtRexTJD4w5nYBVjeyHZjCW6A1DHF6RqRbOd2
44 | bA52XAuKK8ZxgKTbmuQE7wIDAQABo3YwdDAdBgNVHQ4EFgQUzHPVW9zZflquZZSI
45 | iqPZUPkx5YcwHwYDVR0jBBgwFoAUzHPVW9zZflquZZSIiqPZUPkx5YcwDgYDVR0P
46 | AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMA0G
47 | CSqGSIb3DQEBCwUAA4ICAQAoU9mMVuKyYjZhhwigIrbT7EBGd/r2FmRlTOLCnZ0b
48 | sUyfcMfqOhMp0quUK0FBheeO7U7uYb63Fix9La6TKk+dSLRGgev1zrMDXOcup6Nb
49 | hMn62+s7r4ejqr8MTycZue4e3w4V698Odg4vMC8KHRTQhMgC9co/Tk4Q+1/qnSWX
50 | c6jBUO+SVwjM35MwigM09uqfxk4ThDDNJ5t4J2GTpLuLJQ09zLmSb02Shj2Nvb5G
51 | LSQsfGGwIZUZYG37I8ovg2RwKT7P5+2hsFHJJYSaM5s6l97aUh/1yU1s28cEf/7m
52 | RVHWGnulphhUpimCXbrT3jpRVfYitR0Mayr00VsY2q5UrWnJ0U+EXJbLEzmRP/E8
53 | v8R/2Fn9Qng80YwpNO4aZkaoiuQ1jjYVym/MesCSlDT5FE/dx5BMWlrcJtXni5YZ
54 | BOU6Kuyc4bugAw6oUpAd1tihFx9sf4FmKrBwq/v7n9zbaU2omBujN4vsoXMX/xdR
55 | cnqLrINlzFaVzCKuWwXBJKD/G7+d/R4JqUJ3XXZxa+NxmgiwDlgPIBQ6sicVgK4v
56 | Zktp7z0lAlJxpvhp4ToKbJ+OrkKG/0xK1n+16NxNK9kWPRgzegHa3Sm8wowkosap
57 | KFTN0dOrAYBfAC5eAzcssn25wHlDQLW0Lb+KjXxGwDC6mZnhiciFHfSPaPbt9W+z
58 | Ow==
59 | -----END CERTIFICATE-----
60 |
--------------------------------------------------------------------------------
/stormshield/sns/cli.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """ cli to connect to Stormshield Network Security appliances"""
4 |
5 | from __future__ import unicode_literals
6 | import sys
7 | import os
8 | import re
9 | import logging
10 | import logging.handlers
11 | import readline
12 | import getpass
13 | import atexit
14 | import defusedxml.minidom
15 | import argparse
16 | import platform
17 | from pygments import highlight
18 | from pygments.lexers import XmlLexer
19 | from pygments.formatters import TerminalFormatter
20 | from colorlog import LevelFormatter
21 |
22 | from stormshield.sns.sslclient import SSLClient, ServerError, TOTPNeededError
23 | from stormshield.sns.sslclient.__version__ import __version__ as libversion
24 | from urllib3 import __version__ as urllib3version
25 | from requests import __version__ as requestsversion
26 |
27 | # define missing exception for python2
28 | try:
29 | FileNotFoundError
30 | except NameError:
31 | FileNotFoundError = IOError
32 |
33 | OUTPUT_LEVELV_NUM = 60 # log command response
34 | COMMAND_LEVELV_NUM = 59 # log command input
35 | FORMATTER = LevelFormatter(
36 | fmt={
37 | 'DEBUG': "%(log_color)s%(levelname)-8s%(reset)s %(message)s",
38 | 'INFO': "%(log_color)s%(levelname)-8s%(reset)s %(message)s",
39 | 'WARNING': "%(log_color)s%(levelname)-8s%(reset)s %(message)s",
40 | 'ERROR': "%(log_color)s%(levelname)-8s%(reset)s %(message)s",
41 | 'CRITICAL': "%(log_color)s%(levelname)-8s%(reset)s %(message)s",
42 | 'OUTPUT': "%(message)s",
43 | 'COMMAND': "%(message)s"
44 | },
45 | datefmt=None,
46 | reset=True,
47 | log_colors={
48 | 'DEBUG': 'green',
49 | 'INFO': 'cyan',
50 | 'WARNING': 'yellow',
51 | 'ERROR': 'red',
52 | 'CRITICAL': 'red,bg_white'
53 | },
54 | secondary_log_colors={},
55 | style='%'
56 | )
57 |
58 | class CommandFilter(logging.Filter):
59 | def filter(self, record):
60 | if record.levelname == 'COMMAND':
61 | return False
62 | return True
63 |
64 | EMPTY_RE = re.compile(r'^\s*$')
65 |
66 | def make_completer():
67 | """ load completer for readline """
68 | vocabulary = []
69 | with open(SSLClient.get_completer(), "r") as completelist:
70 | for line in completelist:
71 | vocabulary.append(line.replace('.', ' ').strip('\n'))
72 |
73 | def custom_complete(text, state):
74 | results = [x for x in vocabulary if x.startswith(text)] + [None]
75 | return results[state]
76 | return custom_complete
77 |
78 | def main():
79 |
80 | # parse command line
81 |
82 | parser = argparse.ArgumentParser(conflict_handler="resolve")
83 |
84 | group = parser.add_argument_group("Connection parameters")
85 | group.add_argument("-h", "--host", help="Remote UTM", default=None)
86 | group.add_argument("-i", "--ip", help="Remote UTM ip", default=None)
87 | group.add_argument("-P", "--port", help="Remote port", default=443, type=int)
88 | group.add_argument("--proxy", help="Proxy URL (scheme://user:password@host:port)", default=None)
89 | group.add_argument("-t", "--timeout", help="Connection timeout in seconds", default=-1, type=int)
90 |
91 | group = parser.add_argument_group("Authentication parameters")
92 | group.add_argument("-u", "--user", help="User name", default="admin")
93 | group.add_argument("-p", "--password", help="Password", default=None)
94 | group.add_argument("-t", "--totp", help="Time-based one time password", default=None)
95 | group.add_argument("-U", "--usercert", help="User certificate file", default=None)
96 |
97 | group = parser.add_argument_group("SSL parameters")
98 | group.add_argument("-C", "--cabundle", help="CA bundle file", default=None)
99 | group.add_argument("--sslverifypeer", help="Strict SSL CA check", default=True, action="store_true")
100 | group.add_argument("-k", "--no-sslverifypeer", help="Disable strict SSL CA check", default=True, action="store_false", dest="sslverifypeer")
101 | group.add_argument("--sslverifyhost", help="Strict SSL host name check", default=True, action="store_true")
102 | group.add_argument("-K", "--no-sslverifyhost", help="Disable strict SSL host name check", default=True, action="store_false", dest="sslverifyhost")
103 |
104 | group = parser.add_argument_group("Protocol parameters")
105 | group.add_argument("-c", "--credentials", help="Privilege list", default=None)
106 | group.add_argument("-s", "--script", help="Command script", default=None)
107 | group.add_argument("-o", "--outputformat", help="Output format (ini|xml)", default="ini")
108 |
109 | parser.add_argument("--version", help="Library version", default=False, action="store_true")
110 |
111 | group = parser.add_argument_group("Logging parameters")
112 | exclusive = group.add_mutually_exclusive_group()
113 | exclusive.add_argument("-v", "--verbose", help="Increase logging output", default=False, action="store_true")
114 | exclusive.add_argument("-q", "--quiet", help="Decrease logging output", default=False, action="store_true")
115 | group.add_argument("--loglvl", help="Set explicit log level", default=None, choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'])
116 | group.add_argument("--logfile", help='Output log messages to file', default=None)
117 |
118 | args = parser.parse_args()
119 |
120 | host = args.host
121 | ip = args.ip
122 | usercert = args.usercert
123 | cabundle = args.cabundle
124 | password = args.password
125 | totp = args.totp
126 | port = args.port
127 | proxy = args.proxy
128 | timeout = args.timeout
129 | user = args.user
130 | sslverifypeer = args.sslverifypeer
131 | sslverifyhost = args.sslverifyhost
132 | credentials = args.credentials
133 | script = args.script
134 | outputformat = args.outputformat
135 | version = args.version
136 |
137 | # logging
138 |
139 | level = logging.INFO
140 | if args.loglvl is not None:
141 | level = logging.getLevelName(args.loglvl)
142 | elif args.verbose:
143 | level = logging.DEBUG
144 | elif args.quiet:
145 | level = logging.WARNING
146 |
147 | # add custom level
148 | logging.addLevelName(OUTPUT_LEVELV_NUM, "OUTPUT")
149 | logging.addLevelName(COMMAND_LEVELV_NUM, "COMMAND")
150 |
151 | def logoutput(self, message, *args, **kwargs):
152 | # Yes, logger takes its '*args' as 'args'.
153 | self._log(OUTPUT_LEVELV_NUM, message, args, **kwargs)
154 | def logcommand(self, message, *args, **kwargs):
155 | # Yes, logger takes its '*args' as 'args'.
156 | self._log(COMMAND_LEVELV_NUM, message, args, **kwargs)
157 |
158 | logging.Logger.output = logoutput
159 | logging.Logger.command = logcommand
160 |
161 | # logger
162 | logger = logging.getLogger()
163 | for handler in logger.handlers:
164 | logger.removeHandler(handler)
165 | logger.setLevel(level)
166 |
167 | # attach handlers
168 | handler = logging.StreamHandler(sys.stdout)
169 | handler.addFilter(CommandFilter())
170 | logger.addHandler(handler)
171 | if args.logfile is not None:
172 | if platform.system() != 'Windows':
173 | handler = logging.handlers.WatchedFileHandler(args.logfile)
174 | else:
175 | handler = logging.FileHandler(args.logfile)
176 | logger.addHandler(handler)
177 |
178 | for handler in logger.handlers:
179 | if handler.__class__ == logging.StreamHandler:
180 | handler.setFormatter(FORMATTER)
181 |
182 | if version:
183 | logging.info("snscli - stormshield.sns.sslclient version {}".format(libversion))
184 | logging.info(" urllib3 {}".format(urllib3version))
185 | logging.info(" requests {}".format(requestsversion))
186 | sys.exit(0)
187 |
188 | if script is not None:
189 | try:
190 | script = open(script, 'r')
191 | except Exception as exception:
192 | logging.error("Can't open script file - %s", str(exception))
193 | sys.exit(1)
194 |
195 | if outputformat not in ['ini', 'xml']:
196 | logging.error("Unknown output format")
197 | sys.exit(1)
198 |
199 | if host is None:
200 | logging.error("No host provided")
201 | sys.exit(1)
202 |
203 | if password is None and usercert is None:
204 | password = getpass.getpass()
205 |
206 | if timeout == -1:
207 | timeout = None
208 |
209 | # first try without totp, if needed ask for totp
210 | for i in range(0, 2):
211 | try:
212 | client = SSLClient(
213 | host=host, ip=ip, port=port, user=user, password=password, totp=totp,
214 | sslverifypeer=sslverifypeer, sslverifyhost=sslverifyhost,
215 | credentials=credentials, proxy=proxy, timeout=timeout,
216 | usercert=usercert, cabundle=cabundle, autoconnect=False)
217 | except Exception as exception:
218 | logging.error(str(exception))
219 | sys.exit(1)
220 |
221 | try:
222 | client.connect()
223 | except TOTPNeededError as exception:
224 | if i == 0 and totp is None:
225 | logging.warning("Second factor authentication is required.")
226 | totp = getpass.getpass("Totp:")
227 | continue
228 | else:
229 | logging.error(str(exception))
230 | sys.exit(1)
231 | except Exception as exception:
232 | search = re.search(r'doesn\'t match \'(.*)\'', str(exception))
233 | if search:
234 | logging.error(("Appliance name can't be verified, to force connection "
235 | "use \"--host %s --ip %s\" or \"--no-sslverifyhost|-K\" "
236 | "options"), search.group(1), ip if ip is not None else host)
237 | else:
238 | logging.error(str(exception))
239 | sys.exit(1)
240 | else:
241 | break
242 |
243 | # disconnect gracefuly at exit
244 | atexit.register(client.disconnect)
245 |
246 | if script is not None:
247 | for cmd in script.readlines():
248 | cmd = cmd.strip('\r\n')
249 | logger.output(cmd)
250 | if cmd.startswith('#'):
251 | continue
252 | if EMPTY_RE.match(cmd):
253 | continue
254 | try:
255 | response = client.send_command(cmd)
256 | except Exception as exception:
257 | logging.error(str(exception))
258 | sys.exit(1)
259 | if outputformat == 'xml':
260 | logger.output(highlight(defusedxml.minidom.parseString(response.xml).toprettyxml(),
261 | XmlLexer(), TerminalFormatter()))
262 | else:
263 | logger.output(response.output)
264 | sys.exit(0)
265 |
266 | # Start cli
267 |
268 | # load history
269 | histfile = os.path.join(os.path.expanduser("~"), ".sslclient_history")
270 | try:
271 | readline.read_history_file(histfile)
272 | readline.set_history_length(1000)
273 | except FileNotFoundError:
274 | pass
275 |
276 | def save_history(histfile):
277 | try:
278 | readline.write_history_file(histfile)
279 | except:
280 | logging.warning("Can't write history")
281 |
282 | atexit.register(save_history, histfile)
283 |
284 | # load auto-complete
285 | readline.parse_and_bind('tab: complete')
286 | readline.set_completer_delims('')
287 | readline.set_completer(make_completer())
288 |
289 | while True:
290 | try:
291 | cmd = input("> ")
292 | logger.command(cmd)
293 | except EOFError:
294 | break
295 |
296 | # skip comments
297 | if cmd.startswith('#'):
298 | continue
299 |
300 | try:
301 | response = client.send_command(cmd)
302 | except ServerError as exception:
303 | # do not log error on QUIT
304 | if "quit".startswith(cmd.lower()) \
305 | and str(exception) == "Server disconnected":
306 | sys.exit(0)
307 | logging.error(str(exception))
308 | sys.exit(1)
309 | except Exception as exception:
310 | logging.error(str(exception))
311 | sys.exit(1)
312 |
313 | if response.ret == client.SRV_RET_DOWNLOAD:
314 | filename = input("File to save: ")
315 | try:
316 | client.download(filename)
317 | logging.info("File downloaded")
318 | except Exception as exception:
319 | logging.error(str(exception))
320 | elif response.ret == client.SRV_RET_UPLOAD:
321 | filename = input("File to upload: ")
322 | try:
323 | client.upload(filename)
324 | logging.info("File uploaded")
325 | except Exception as exception:
326 | logging.error(str(exception))
327 | else:
328 | if outputformat == 'xml':
329 | logger.output(highlight(defusedxml.minidom.parseString(response.xml).toprettyxml(),
330 | XmlLexer(), TerminalFormatter()))
331 | else:
332 | logger.output(response.output)
333 |
334 | # use correct input function with python2
335 | try:
336 | input = raw_input
337 | except NameError:
338 | pass
339 |
340 | if __name__ == "__main__":
341 | # execute only if run as a script
342 | main()
343 |
--------------------------------------------------------------------------------
/stormshield/sns/cmd.complete:
--------------------------------------------------------------------------------
1 | auth
2 | cache
3 | cancel
4 | certificate
5 | chpwd
6 | config
7 | config.activate
8 | config.antispam
9 | config.antispam.activate
10 | config.antispam.blacklist
11 | config.antispam.blacklist.add
12 | config.antispam.blacklist.list
13 | config.antispam.blacklist.remove
14 | config.antispam.dnsbl
15 | config.antispam.dnsbl.add
16 | config.antispam.dnsbl.edit
17 | config.antispam.dnsbl.list
18 | config.antispam.dnsbl.remove
19 | config.antispam.dnsbl.set
20 | config.antispam.dnsbl.show
21 | config.antispam.set
22 | config.antispam.show
23 | config.antispam.vr
24 | config.antispam.vr.set
25 | config.antispam.vr.show
26 | config.antispam.whitelist
27 | config.antispam.whitelist.add
28 | config.antispam.whitelist.list
29 | config.antispam.whitelist.remove
30 | config.antivirus
31 | config.antivirus.activate
32 | config.antivirus.cleanup
33 | config.antivirus.erasekav
34 | config.antivirus.licence
35 | config.antivirus.list
36 | config.antivirus.objects
37 | config.antivirus.select
38 | config.antivirus.services
39 | config.antivirus.services.ftp
40 | config.antivirus.services.pop3
41 | config.antivirus.services.show
42 | config.antivirus.services.smtp
43 | config.antivirus.show
44 | config.auth
45 | config.auth.activate
46 | config.auth.advanced
47 | config.auth.agent
48 | config.auth.agentignore
49 | config.auth.agentignore.add
50 | config.auth.agentignore.remove
51 | config.auth.agentignore.show
52 | config.auth.default
53 | config.auth.guest
54 | config.auth.https
55 | config.auth.interface
56 | config.auth.interface.advanced
57 | config.auth.interface.enrolment
58 | config.auth.interface.list
59 | config.auth.interface.method
60 | config.auth.interface.password
61 | config.auth.interface.rename
62 | config.auth.interface.show
63 | config.auth.interface.state
64 | config.auth.interface.time
65 | config.auth.interface.timerange
66 | config.auth.kerberos
67 | config.auth.ldap
68 | config.auth.ldap.voucher
69 | config.auth.ldap.voucher.activate
70 | config.auth.ldap.voucher.show
71 | config.auth.ldap.voucher.shrink
72 | config.auth.ldap.voucher.state
73 | config.auth.ldap.voucher.status
74 | config.auth.map
75 | config.auth.map.add
76 | config.auth.map.clear
77 | config.auth.map.list
78 | config.auth.map.remove
79 | config.auth.multiuser
80 | config.auth.multiuser.add
81 | config.auth.multiuser.list
82 | config.auth.multiuser.remove
83 | config.auth.radius
84 | config.auth.show
85 | config.auth.spnego
86 | config.auth.sponsor
87 | config.auth.ssl
88 | config.auth.ssl.caverify
89 | config.auth.ssl.caverify.add
90 | config.auth.ssl.caverify.remove
91 | config.auth.ssl.certidentifier
92 | config.auth.ssl.ldapidentifier
93 | config.auth.ssl.ldaplookup
94 | config.auth.ssl.ldaplookup.add
95 | config.auth.ssl.ldaplookup.list
96 | config.auth.ssl.ldaplookup.method
97 | config.auth.ssl.ldaplookup.move
98 | config.auth.ssl.ldaplookup.remove
99 | config.auth.ssl.ldaplookup.show
100 | config.auth.ssl.update
101 | config.autobackup
102 | config.autobackup.activate
103 | config.autobackup.launch
104 | config.autobackup.restore
105 | config.autobackup.set
106 | config.autobackup.show
107 | config.autoupdate
108 | config.autoupdate.activate
109 | config.autoupdate.list
110 | config.autoupdate.server
111 | config.autoupdate.show
112 | config.autoupdate.state
113 | config.backup
114 | config.bird
115 | config.bird.activate
116 | config.bird.show
117 | config.bird.state
118 | config.bird.update
119 | config.communication
120 | config.communication.activate
121 | config.communication.email
122 | config.communication.email.group
123 | config.communication.email.group.activate
124 | config.communication.email.group.addrecipient
125 | config.communication.email.group.check
126 | config.communication.email.group.create
127 | config.communication.email.group.delrecipient
128 | config.communication.email.group.edit
129 | config.communication.email.group.list
130 | config.communication.email.group.remove
131 | config.communication.email.group.rename
132 | config.communication.email.template
133 | config.communication.email.template.default
134 | config.communication.email.template.download
135 | config.communication.email.template.list
136 | config.communication.email.template.upload
137 | config.communication.httpproxy
138 | config.communication.ipfix
139 | config.communication.ipfix.show
140 | config.communication.ipfix.update
141 | config.communication.show
142 | config.communication.smtp
143 | config.communication.syslog
144 | config.communication.syslog.profile
145 | config.communication.syslog.profile.show
146 | config.communication.syslog.profile.update
147 | config.communication.test
148 | config.communication.test.smtp
149 | config.console
150 | config.console.activate
151 | config.console.gethostkey
152 | config.console.getkey
153 | config.console.remoteadmin
154 | config.console.setpassphrase
155 | config.console.ssh
156 | config.crypto
157 | config.ddnsclient
158 | config.ddnsclient.activate
159 | config.ddnsclient.delete
160 | config.ddnsclient.list
161 | config.ddnsclient.new
162 | config.ddnsclient.resetevent
163 | config.ddnsclient.set
164 | config.ddnsclient.show
165 | config.ddnsclient.unset
166 | config.dhcp
167 | config.dhcp.activate
168 | config.dhcp.host
169 | config.dhcp.host.add
170 | config.dhcp.host.list
171 | config.dhcp.host.remove
172 | config.dhcp.parameters
173 | config.dhcp.parameters.add
174 | config.dhcp.parameters.list
175 | config.dhcp.parameters.remove
176 | config.dhcp.range
177 | config.dhcp.range.add
178 | config.dhcp.range.list
179 | config.dhcp.range.remove
180 | config.dhcp.relay
181 | config.dhcp.relay.advanced
182 | config.dhcp.relay.interface
183 | config.dhcp.relay.interface.add
184 | config.dhcp.relay.interface.all
185 | config.dhcp.relay.interface.list
186 | config.dhcp.relay.interface.remove
187 | config.dhcp.relay.server
188 | config.dhcp.relay.show
189 | config.dhcp.relay.state
190 | config.dhcp.servers
191 | config.dhcp.servers.add
192 | config.dhcp.servers.list
193 | config.dhcp.servers.remove
194 | config.dhcp.show
195 | config.dhcp.state
196 | config.dhcp6
197 | config.dhcp6.activate
198 | config.dhcp6.host
199 | config.dhcp6.host.add
200 | config.dhcp6.host.list
201 | config.dhcp6.host.remove
202 | config.dhcp6.parameters
203 | config.dhcp6.parameters.add
204 | config.dhcp6.parameters.list
205 | config.dhcp6.parameters.remove
206 | config.dhcp6.range
207 | config.dhcp6.range.add
208 | config.dhcp6.range.list
209 | config.dhcp6.range.remove
210 | config.dhcp6.relay
211 | config.dhcp6.relay.fwdinterface
212 | config.dhcp6.relay.fwdinterface.add
213 | config.dhcp6.relay.fwdinterface.list
214 | config.dhcp6.relay.fwdinterface.remove
215 | config.dhcp6.relay.rcvinterface
216 | config.dhcp6.relay.rcvinterface.add
217 | config.dhcp6.relay.rcvinterface.list
218 | config.dhcp6.relay.rcvinterface.remove
219 | config.dhcp6.relay.server
220 | config.dhcp6.relay.show
221 | config.dhcp6.relay.state
222 | config.dhcp6.servers
223 | config.dhcp6.servers.add
224 | config.dhcp6.servers.list
225 | config.dhcp6.servers.remove
226 | config.dhcp6.show
227 | config.dhcp6.state
228 | config.dns
229 | config.dns.activate
230 | config.dns.advanced
231 | config.dns.client
232 | config.dns.client.add
233 | config.dns.client.list
234 | config.dns.client.remove
235 | config.dns.server
236 | config.dns.server.add
237 | config.dns.server.list
238 | config.dns.server.remove
239 | config.dns.show
240 | config.dns.state
241 | config.dns.useroot
242 | config.download
243 | config.filter
244 | config.filter.activate
245 | config.filter.check
246 | config.filter.default
247 | config.filter.explicit
248 | config.filter.export
249 | config.filter.implicit
250 | config.filter.manage
251 | config.filter.rule
252 | config.filter.rule.addsep
253 | config.filter.rule.collapse
254 | config.filter.rule.copy
255 | config.filter.rule.insert
256 | config.filter.rule.move
257 | config.filter.rule.remove
258 | config.filter.rule.update
259 | config.filter.show
260 | config.fwadmin
261 | config.fwadmin.activate
262 | config.fwadmin.update
263 | config.global
264 | config.global.object
265 | config.global.object.export
266 | config.global.object.fqdn
267 | config.global.object.fqdn.check
268 | config.global.object.fqdn.delete
269 | config.global.object.fqdn.new
270 | config.global.object.fqdn.show
271 | config.global.object.geogroup
272 | config.global.object.geogroup.addto
273 | config.global.object.geogroup.check
274 | config.global.object.geogroup.delete
275 | config.global.object.geogroup.new
276 | config.global.object.geogroup.removefrom
277 | config.global.object.geogroup.show
278 | config.global.object.get
279 | config.global.object.group
280 | config.global.object.group.addto
281 | config.global.object.group.check
282 | config.global.object.group.delete
283 | config.global.object.group.new
284 | config.global.object.group.removefrom
285 | config.global.object.group.show
286 | config.global.object.host
287 | config.global.object.host.check
288 | config.global.object.host.delete
289 | config.global.object.host.new
290 | config.global.object.import
291 | config.global.object.import.activate
292 | config.global.object.import.cancel
293 | config.global.object.import.status
294 | config.global.object.import.upload
295 | config.global.object.iprepgroup
296 | config.global.object.iprepgroup.addto
297 | config.global.object.iprepgroup.check
298 | config.global.object.iprepgroup.delete
299 | config.global.object.iprepgroup.new
300 | config.global.object.iprepgroup.removefrom
301 | config.global.object.iprepgroup.show
302 | config.global.object.network
303 | config.global.object.network.check
304 | config.global.object.network.delete
305 | config.global.object.network.new
306 | config.global.object.protocol
307 | config.global.object.protocol.check
308 | config.global.object.protocol.delete
309 | config.global.object.protocol.new
310 | config.global.object.rename
311 | config.global.object.router
312 | config.global.object.router.check
313 | config.global.object.router.delete
314 | config.global.object.router.gateway
315 | config.global.object.router.gateway.add
316 | config.global.object.router.gateway.move
317 | config.global.object.router.gateway.remove
318 | config.global.object.router.gateway.update
319 | config.global.object.router.new
320 | config.global.object.router.show
321 | config.global.object.service
322 | config.global.object.service.check
323 | config.global.object.service.delete
324 | config.global.object.service.new
325 | config.global.object.servicegroup
326 | config.global.object.servicegroup.addto
327 | config.global.object.servicegroup.check
328 | config.global.object.servicegroup.delete
329 | config.global.object.servicegroup.new
330 | config.global.object.servicegroup.removefrom
331 | config.global.object.servicegroup.show
332 | config.global.object.time
333 | config.global.object.time.check
334 | config.global.object.time.delete
335 | config.global.object.time.new
336 | config.ha
337 | config.ha.activate
338 | config.ha.create
339 | config.ha.join
340 | config.ha.show
341 | config.ha.state
342 | config.ha.update
343 | config.ha.weight
344 | config.ha.weight.activate
345 | config.ha.weight.show
346 | config.ha.weight.update
347 | config.hostrep
348 | config.hostrep.activate
349 | config.hostrep.hostlist
350 | config.hostrep.hostlist.add
351 | config.hostrep.hostlist.clear
352 | config.hostrep.hostlist.remove
353 | config.hostrep.hostlist.show
354 | config.hostrep.show
355 | config.hostrep.update
356 | config.ipsec
357 | config.ipsec.activate
358 | config.ipsec.ca
359 | config.ipsec.ca.add
360 | config.ipsec.ca.list
361 | config.ipsec.ca.remove
362 | config.ipsec.check
363 | config.ipsec.ldaplookup
364 | config.ipsec.ldaplookup.list
365 | config.ipsec.ldaplookup.method
366 | config.ipsec.ldaplookup.show
367 | config.ipsec.ldaplookup.update
368 | config.ipsec.peer
369 | config.ipsec.peer.check
370 | config.ipsec.peer.list
371 | config.ipsec.peer.new
372 | config.ipsec.peer.remove
373 | config.ipsec.peer.rename
374 | config.ipsec.peer.show
375 | config.ipsec.peer.update
376 | config.ipsec.policy
377 | config.ipsec.policy.gateway
378 | config.ipsec.policy.gateway.add
379 | config.ipsec.policy.gateway.addsep
380 | config.ipsec.policy.gateway.collapse
381 | config.ipsec.policy.gateway.list
382 | config.ipsec.policy.gateway.move
383 | config.ipsec.policy.gateway.remove
384 | config.ipsec.policy.gateway.update
385 | config.ipsec.policy.mobile
386 | config.ipsec.policy.mobile.add
387 | config.ipsec.policy.mobile.addsep
388 | config.ipsec.policy.mobile.collapse
389 | config.ipsec.policy.mobile.getpeer
390 | config.ipsec.policy.mobile.list
391 | config.ipsec.policy.mobile.move
392 | config.ipsec.policy.mobile.remove
393 | config.ipsec.policy.mobile.setpeer
394 | config.ipsec.policy.mobile.update
395 | config.ipsec.profile
396 | config.ipsec.profile.phase1
397 | config.ipsec.profile.phase1.addprop
398 | config.ipsec.profile.phase1.check
399 | config.ipsec.profile.phase1.getdefault
400 | config.ipsec.profile.phase1.list
401 | config.ipsec.profile.phase1.moveprop
402 | config.ipsec.profile.phase1.new
403 | config.ipsec.profile.phase1.remove
404 | config.ipsec.profile.phase1.removeprop
405 | config.ipsec.profile.phase1.setdefault
406 | config.ipsec.profile.phase1.show
407 | config.ipsec.profile.phase1.update
408 | config.ipsec.profile.phase2
409 | config.ipsec.profile.phase2.check
410 | config.ipsec.profile.phase2.getdefault
411 | config.ipsec.profile.phase2.list
412 | config.ipsec.profile.phase2.new
413 | config.ipsec.profile.phase2.remove
414 | config.ipsec.profile.phase2.setdefault
415 | config.ipsec.profile.phase2.show
416 | config.ipsec.profile.phase2.update
417 | config.ipsec.property
418 | config.ipsec.psk
419 | config.ipsec.psk.add
420 | config.ipsec.psk.list
421 | config.ipsec.psk.remove
422 | config.ipsec.show
423 | config.ipsec.update
424 | config.key
425 | config.key.add
426 | config.key.list
427 | config.key.remove
428 | config.ldap
429 | config.ldap.activate
430 | config.ldap.check
431 | config.ldap.count
432 | config.ldap.default
433 | config.ldap.delmap
434 | config.ldap.external
435 | config.ldap.initialize
436 | config.ldap.list
437 | config.ldap.password
438 | config.ldap.public
439 | config.ldap.remove
440 | config.ldap.rename
441 | config.ldap.setmap
442 | config.ldap.show
443 | config.ldap.state
444 | config.ldap.update
445 | config.ldap.usage
446 | config.log
447 | config.log.activate
448 | config.log.alarm
449 | config.log.auth
450 | config.log.communication
451 | config.log.communication.email
452 | config.log.communication.snmp
453 | config.log.connection
454 | config.log.filter
455 | config.log.ftp
456 | config.log.monitor
457 | config.log.plugin
458 | config.log.pop3
459 | config.log.pvm
460 | config.log.sandboxing
461 | config.log.server
462 | config.log.show
463 | config.log.smtp
464 | config.log.ssl
465 | config.log.stat
466 | config.log.system
467 | config.log.vpn
468 | config.log.web
469 | config.log.xvpn
470 | config.mailfiltering
471 | config.mailfiltering.activate
472 | config.mailfiltering.copy
473 | config.mailfiltering.default
474 | config.mailfiltering.list
475 | config.mailfiltering.rule
476 | config.mailfiltering.rule.insert
477 | config.mailfiltering.rule.move
478 | config.mailfiltering.rule.remove
479 | config.mailfiltering.rule.show
480 | config.mailfiltering.rule.update
481 | config.mailfiltering.update
482 | config.modem
483 | config.modem.activate
484 | config.modem.show
485 | config.modem.update
486 | config.network
487 | config.network.activate
488 | config.network.defaultroute
489 | config.network.defaultroute.activate
490 | config.network.defaultroute.set
491 | config.network.defaultroute.show
492 | config.network.gateway
493 | config.network.gateway.activate
494 | config.network.gateway.add
495 | config.network.gateway.ipv6
496 | config.network.gateway.ipv6.add
497 | config.network.gateway.ipv6.remove
498 | config.network.gateway.ipv6.set
499 | config.network.gateway.ipv6.show
500 | config.network.gateway.ipv6.update
501 | config.network.gateway.remove
502 | config.network.gateway.set
503 | config.network.gateway.show
504 | config.network.gateway.update
505 | config.network.interface
506 | config.network.interface.activate
507 | config.network.interface.address
508 | config.network.interface.address.add
509 | config.network.interface.address.remove
510 | config.network.interface.address.update
511 | config.network.interface.aggregate
512 | config.network.interface.capabilities
513 | config.network.interface.check
514 | config.network.interface.create
515 | config.network.interface.ipsec
516 | config.network.interface.ipv6
517 | config.network.interface.ipv6.address
518 | config.network.interface.ipv6.address.add
519 | config.network.interface.ipv6.address.remove
520 | config.network.interface.ipv6.address.update
521 | config.network.interface.ipv6.routeradv
522 | config.network.interface.ipv6.routeradv.config
523 | config.network.interface.ipv6.routeradv.prefix
524 | config.network.interface.ipv6.routeradv.prefix.add
525 | config.network.interface.ipv6.routeradv.prefix.remove
526 | config.network.interface.ipv6.routeradv.prefix.update
527 | config.network.interface.limit
528 | config.network.interface.limit.show
529 | config.network.interface.msti
530 | config.network.interface.msti.add
531 | config.network.interface.msti.remove
532 | config.network.interface.remove
533 | config.network.interface.rename
534 | config.network.interface.show
535 | config.network.interface.update
536 | config.network.ipv6
537 | config.network.ipv6.state
538 | config.network.route
539 | config.network.route.activate
540 | config.network.route.add
541 | config.network.route.ipv6
542 | config.network.route.ipv6.add
543 | config.network.route.ipv6.remove
544 | config.network.route.ipv6.reverse
545 | config.network.route.ipv6.reverse.add
546 | config.network.route.ipv6.reverse.remove
547 | config.network.route.ipv6.reverse.show
548 | config.network.route.ipv6.reverse.update
549 | config.network.route.ipv6.show
550 | config.network.route.ipv6.update
551 | config.network.route.remove
552 | config.network.route.reverse
553 | config.network.route.reverse.add
554 | config.network.route.reverse.remove
555 | config.network.route.reverse.show
556 | config.network.route.reverse.update
557 | config.network.route.show
558 | config.network.route.update
559 | config.network.switch
560 | config.network.switch.activate
561 | config.network.switch.add
562 | config.network.switch.modify
563 | config.network.switch.show
564 | config.ntp
565 | config.ntp.activate
566 | config.ntp.advanced
567 | config.ntp.key
568 | config.ntp.key.add
569 | config.ntp.key.list
570 | config.ntp.key.remove
571 | config.ntp.server
572 | config.ntp.server.add
573 | config.ntp.server.list
574 | config.ntp.server.remove
575 | config.ntp.show
576 | config.ntp.state
577 | config.object
578 | config.object.activate
579 | config.object.cncategorygroup
580 | config.object.cncategorygroup.addto
581 | config.object.cncategorygroup.check
582 | config.object.cncategorygroup.delete
583 | config.object.cncategorygroup.new
584 | config.object.cncategorygroup.removefrom
585 | config.object.cncategorygroup.show
586 | config.object.export
587 | config.object.fqdn
588 | config.object.fqdn.check
589 | config.object.fqdn.delete
590 | config.object.fqdn.new
591 | config.object.fqdn.show
592 | config.object.geogroup
593 | config.object.geogroup.addto
594 | config.object.geogroup.check
595 | config.object.geogroup.delete
596 | config.object.geogroup.new
597 | config.object.geogroup.removefrom
598 | config.object.geogroup.show
599 | config.object.get
600 | config.object.group
601 | config.object.group.addto
602 | config.object.group.check
603 | config.object.group.delete
604 | config.object.group.new
605 | config.object.group.removefrom
606 | config.object.group.show
607 | config.object.host
608 | config.object.host.check
609 | config.object.host.delete
610 | config.object.host.new
611 | config.object.import
612 | config.object.import.activate
613 | config.object.import.cancel
614 | config.object.import.status
615 | config.object.import.upload
616 | config.object.internet
617 | config.object.internet.show
618 | config.object.internet.update
619 | config.object.iprepgroup
620 | config.object.iprepgroup.addto
621 | config.object.iprepgroup.check
622 | config.object.iprepgroup.delete
623 | config.object.iprepgroup.new
624 | config.object.iprepgroup.removefrom
625 | config.object.iprepgroup.show
626 | config.object.list
627 | config.object.network
628 | config.object.network.check
629 | config.object.network.delete
630 | config.object.network.new
631 | config.object.protocol
632 | config.object.protocol.check
633 | config.object.protocol.delete
634 | config.object.protocol.new
635 | config.object.qos
636 | config.object.qos.activate
637 | config.object.qos.drop
638 | config.object.qos.interface.set
639 | config.object.qos.interface.show
640 | config.object.qos.interface.remove
641 | config.object.qos.qid
642 | config.object.qos.qid.add
643 | config.object.qos.qid.check
644 | config.object.qos.qid.list
645 | config.object.qos.qid.remove
646 | config.object.qos.qid.rename
647 | config.object.qos.set
648 | config.object.qos.tbr.set
649 | config.object.qos.tbr.show
650 | config.object.qos.tbr.remove
651 | config.object.qos.show
652 | config.object.rename
653 | config.object.router
654 | config.object.router.check
655 | config.object.router.delete
656 | config.object.router.gateway
657 | config.object.router.gateway.add
658 | config.object.router.gateway.move
659 | config.object.router.gateway.remove
660 | config.object.router.gateway.update
661 | config.object.router.new
662 | config.object.router.show
663 | config.object.service
664 | config.object.service.check
665 | config.object.service.delete
666 | config.object.service.new
667 | config.object.servicegroup
668 | config.object.servicegroup.addto
669 | config.object.servicegroup.check
670 | config.object.servicegroup.delete
671 | config.object.servicegroup.new
672 | config.object.servicegroup.removefrom
673 | config.object.servicegroup.show
674 | config.object.time
675 | config.object.time.check
676 | config.object.time.delete
677 | config.object.time.new
678 | config.object.urlcategorygroup
679 | config.object.urlcategorygroup.addto
680 | config.object.urlcategorygroup.check
681 | config.object.urlcategorygroup.delete
682 | config.object.urlcategorygroup.new
683 | config.object.urlcategorygroup.removefrom
684 | config.object.urlcategorygroup.show
685 | config.object.urlgroup
686 | config.object.urlgroup.addto
687 | config.object.urlgroup.check
688 | config.object.urlgroup.classify
689 | config.object.urlgroup.delete
690 | config.object.urlgroup.new
691 | config.object.urlgroup.removefrom
692 | config.object.urlgroup.setbase
693 | config.object.urlgroup.show
694 | config.openvpn
695 | config.openvpn.activate
696 | config.openvpn.default
697 | config.openvpn.download
698 | config.openvpn.list
699 | config.openvpn.show
700 | config.openvpn.update
701 | config.passwdpolicy
702 | config.passwdpolicy.activate
703 | config.passwdpolicy.set
704 | config.passwdpolicy.show
705 | config.pptp
706 | config.pptp.activate
707 | config.pptp.advanced
708 | config.pptp.method
709 | config.pptp.pool
710 | config.pptp.show
711 | config.pptp.state
712 | config.pptp.user
713 | config.pptp.user.activate
714 | config.pptp.user.add
715 | config.pptp.user.list
716 | config.pptp.user.remove
717 | config.protocol
718 | config.protocol.activate
719 | config.protocol.common
720 | config.protocol.common.config
721 | config.protocol.common.default
722 | config.protocol.common.ips
723 | config.protocol.common.ips.config
724 | config.protocol.common.show
725 | config.protocol.dcerpc_tcp.profile.ips.uuid
726 | config.protocol.dcerpc_tcp.profile.ips.uuid.insert
727 | config.protocol.dcerpc_tcp.profile.ips.uuid.remove
728 | config.protocol.dcerpc_tcp.profile.ips.uuid.show
729 | config.protocol.dcerpc_tcp.profile.ips.uuid.update
730 | config.protocol.enip_tcp.profile.ips.cipservice
731 | config.protocol.enip_tcp.profile.ips.cipservice.insert
732 | config.protocol.enip_tcp.profile.ips.cipservice.remove
733 | config.protocol.enip_tcp.profile.ips.cipservice.show
734 | config.protocol.enip_tcp.profile.ips.cipservice.update
735 | config.protocol.enip_udp.profile.ips.cipservice
736 | config.protocol.enip_udp.profile.ips.cipservice.insert
737 | config.protocol.enip_udp.profile.ips.cipservice.remove
738 | config.protocol.enip_udp.profile.ips.cipservice.show
739 | config.protocol.enip_udp.profile.ips.cipservice.update
740 | config.protocol.ftp.common.proxy
741 | config.protocol.ftp.common.proxy.config
742 | config.protocol.ftp.profile.proxy
743 | config.protocol.ftp.profile.proxy.antivirus
744 | config.protocol.ftp.profile.proxy.cmd
745 | config.protocol.ftp.profile.proxy.config
746 | config.protocol.ftp.profile.proxy.extracmd
747 | config.protocol.ftp.profile.proxy.extracmd.add
748 | config.protocol.ftp.profile.proxy.extracmd.list
749 | config.protocol.ftp.profile.proxy.extracmd.remove
750 | config.protocol.ftp.profile.proxy.postproc
751 | config.protocol.ftp.profile.proxy.sandboxing
752 | config.protocol.ftp.profile.proxy.sandboxing.policy
753 | config.protocol.ftp.profile.proxy.sandboxing.type
754 | config.protocol.ftp.profile.proxy.sandboxing.type.show
755 | config.protocol.ftp.profile.proxy.sandboxing.type.update
756 | config.protocol.http.common.proxy
757 | config.protocol.http.common.proxy.config
758 | config.protocol.http.profile.proxy
759 | config.protocol.http.profile.proxy.antivirus
760 | config.protocol.http.profile.proxy.config
761 | config.protocol.http.profile.proxy.icapexclude
762 | config.protocol.http.profile.proxy.icapexclude.add
763 | config.protocol.http.profile.proxy.icapexclude.list
764 | config.protocol.http.profile.proxy.icapexclude.remove
765 | config.protocol.http.profile.proxy.icapreqmod
766 | config.protocol.http.profile.proxy.icaprespmod
767 | config.protocol.http.profile.proxy.mime
768 | config.protocol.http.profile.proxy.mime.insert
769 | config.protocol.http.profile.proxy.mime.move
770 | config.protocol.http.profile.proxy.mime.remove
771 | config.protocol.http.profile.proxy.mime.show
772 | config.protocol.http.profile.proxy.mime.update
773 | config.protocol.http.profile.proxy.postproc
774 | config.protocol.http.profile.proxy.sandboxing
775 | config.protocol.http.profile.proxy.sandboxing.policy
776 | config.protocol.http.profile.proxy.sandboxing.type
777 | config.protocol.http.profile.proxy.sandboxing.type.show
778 | config.protocol.http.profile.proxy.sandboxing.type.update
779 | config.protocol.http.profile.proxy.urlfiltering
780 | config.protocol.iec104.profile.ips.cause
781 | config.protocol.iec104.profile.ips.cause.config
782 | config.protocol.iec104.profile.ips.cause.list
783 | config.protocol.ip.common.inputloadbalance
784 | config.protocol.ip.common.ips.fragment
785 | config.protocol.list
786 | config.protocol.modbus.profile.ips.memoryaccess
787 | config.protocol.modbus.profile.ips.memoryaccess.config
788 | config.protocol.nb-cifs_tcp.profile.ips.uuid
789 | config.protocol.nb-cifs_tcp.profile.ips.uuid.insert
790 | config.protocol.nb-cifs_tcp.profile.ips.uuid.remove
791 | config.protocol.nb-cifs_tcp.profile.ips.uuid.show
792 | config.protocol.nb-cifs_tcp.profile.ips.uuid.update
793 | config.protocol.nb-epmap_tcp.profile.ips.uuid
794 | config.protocol.nb-epmap_tcp.profile.ips.uuid.insert
795 | config.protocol.nb-epmap_tcp.profile.ips.uuid.remove
796 | config.protocol.nb-epmap_tcp.profile.ips.uuid.show
797 | config.protocol.nb-epmap_tcp.profile.ips.uuid.update
798 | config.protocol.nb-ssn.profile.ips.uuid
799 | config.protocol.nb-ssn.profile.ips.uuid.insert
800 | config.protocol.nb-ssn.profile.ips.uuid.remove
801 | config.protocol.nb-ssn.profile.ips.uuid.show
802 | config.protocol.nb-ssn.profile.ips.uuid.update
803 | config.protocol.oracle-tns.profile.ips.hosts
804 | config.protocol.oracle-tns.profile.ips.hosts.insert
805 | config.protocol.oracle-tns.profile.ips.hosts.remove
806 | config.protocol.oracle-tns.profile.ips.hosts.show
807 | config.protocol.pop3.common.proxy
808 | config.protocol.pop3.common.proxy.config
809 | config.protocol.pop3.profile.proxy
810 | config.protocol.pop3.profile.proxy.antivirus
811 | config.protocol.pop3.profile.proxy.cmd
812 | config.protocol.pop3.profile.proxy.config
813 | config.protocol.pop3.profile.proxy.extracmd
814 | config.protocol.pop3.profile.proxy.extracmd.add
815 | config.protocol.pop3.profile.proxy.extracmd.list
816 | config.protocol.pop3.profile.proxy.extracmd.remove
817 | config.protocol.pop3.profile.proxy.postproc
818 | config.protocol.pop3.profile.proxy.sandboxing
819 | config.protocol.pop3.profile.proxy.sandboxing.maxsize
820 | config.protocol.pop3.profile.proxy.sandboxing.maxsize.set
821 | config.protocol.pop3.profile.proxy.sandboxing.maxsize.show
822 | config.protocol.pop3.profile.proxy.sandboxing.policy
823 | config.protocol.pop3.profile.proxy.sandboxing.type
824 | config.protocol.pop3.profile.proxy.sandboxing.type.show
825 | config.protocol.pop3.profile.proxy.sandboxing.type.update
826 | config.protocol.profile
827 | config.protocol.profile.alarm
828 | config.protocol.profile.alarm.default
829 | config.protocol.profile.alarm.show
830 | config.protocol.profile.alarm.update
831 | config.protocol.profile.check
832 | config.protocol.profile.copy
833 | config.protocol.profile.default
834 | config.protocol.profile.ips
835 | config.protocol.profile.ips.config
836 | config.protocol.profile.list
837 | config.protocol.profile.show
838 | config.protocol.profile.update
839 | config.protocol.show
840 | config.protocol.smtp.common.proxy
841 | config.protocol.smtp.common.proxy.config
842 | config.protocol.smtp.profile.proxy
843 | config.protocol.smtp.profile.proxy.antivirus
844 | config.protocol.smtp.profile.proxy.cmd
845 | config.protocol.smtp.profile.proxy.config
846 | config.protocol.smtp.profile.proxy.extracmd
847 | config.protocol.smtp.profile.proxy.extracmd.add
848 | config.protocol.smtp.profile.proxy.extracmd.list
849 | config.protocol.smtp.profile.proxy.extracmd.remove
850 | config.protocol.smtp.profile.proxy.postproc
851 | config.protocol.smtp.profile.proxy.sandboxing
852 | config.protocol.smtp.profile.proxy.sandboxing.maxsize
853 | config.protocol.smtp.profile.proxy.sandboxing.maxsize.set
854 | config.protocol.smtp.profile.proxy.sandboxing.maxsize.show
855 | config.protocol.smtp.profile.proxy.sandboxing.policy
856 | config.protocol.smtp.profile.proxy.sandboxing.type
857 | config.protocol.smtp.profile.proxy.sandboxing.type.show
858 | config.protocol.smtp.profile.proxy.sandboxing.type.update
859 | config.protocol.ssl.common.proxy
860 | config.protocol.ssl.common.proxy.ca
861 | config.protocol.ssl.common.proxy.ca.custom
862 | config.protocol.ssl.common.proxy.ca.custom.add
863 | config.protocol.ssl.common.proxy.ca.custom.list
864 | config.protocol.ssl.common.proxy.ca.custom.remove
865 | config.protocol.ssl.common.proxy.ca.trusted
866 | config.protocol.ssl.common.proxy.ca.trusted.disable
867 | config.protocol.ssl.common.proxy.ca.trusted.enable
868 | config.protocol.ssl.common.proxy.ca.trusted.list
869 | config.protocol.ssl.common.proxy.cert
870 | config.protocol.ssl.common.proxy.cert.trusted
871 | config.protocol.ssl.common.proxy.cert.trusted.add
872 | config.protocol.ssl.common.proxy.cert.trusted.list
873 | config.protocol.ssl.common.proxy.cert.trusted.remove
874 | config.protocol.ssl.common.proxy.config
875 | config.protocol.ssl.common.proxy.sslprotocol
876 | config.protocol.ssl.profile.proxy
877 | config.protocol.ssl.profile.proxy.config
878 | config.protocol.ssl.profile.proxy.sslfiltering
879 | config.protocol.tcpudp.common.ips.connection
880 | config.protocol.tcpudp.profile.ips.connection
881 | config.protocol.tcpudp.profile.ips.synproxy
882 | config.pvm
883 | config.pvm.activate
884 | config.pvm.data
885 | config.pvm.data.family
886 | config.pvm.data.severity
887 | config.pvm.data.vuln
888 | config.pvm.email
889 | config.pvm.hostlist
890 | config.pvm.hostlist.add
891 | config.pvm.hostlist.clear
892 | config.pvm.hostlist.remove
893 | config.pvm.hostlist.show
894 | config.pvm.profile
895 | config.pvm.profile.clear
896 | config.pvm.profile.create
897 | config.pvm.profile.line
898 | config.pvm.profile.line.add
899 | config.pvm.profile.line.remove
900 | config.pvm.profile.line.update
901 | config.pvm.profile.list
902 | config.pvm.profile.remove
903 | config.pvm.profile.show
904 | config.pvm.profile.update
905 | config.pvm.profile.vuln
906 | config.pvm.profile.vuln.add
907 | config.pvm.profile.vuln.clear
908 | config.pvm.profile.vuln.remove
909 | config.pvm.profile.vuln.show
910 | config.pvm.show
911 | config.pvm.state
912 | config.pvm.timeout
913 | config.raid
914 | config.raid.create
915 | config.raid.hotspare
916 | config.raid.rebuild
917 | config.report
918 | config.report.activate
919 | config.report.show
920 | config.report.state
921 | config.report.update
922 | config.restore
923 | config.sandboxing
924 | config.sandboxing.activate
925 | config.sandboxing.set
926 | config.sandboxing.show
927 | config.secure
928 | config.secure.add
929 | config.secure.backup
930 | config.secure.initialize
931 | config.secure.list
932 | config.secure.load
933 | config.secure.remove
934 | config.secure.restore
935 | config.secure.show
936 | config.secure.state
937 | config.secure.sync
938 | config.secure.usbconf
939 | config.securityinspection
940 | config.securityinspection.activate
941 | config.securityinspection.common
942 | config.securityinspection.common.addresslist
943 | config.securityinspection.common.addresslist.add
944 | config.securityinspection.common.addresslist.remove
945 | config.securityinspection.common.addresslist.show
946 | config.securityinspection.common.alarm
947 | config.securityinspection.common.alarm.list
948 | config.securityinspection.common.alarm.new
949 | config.securityinspection.common.alarm.new.config
950 | config.securityinspection.common.alarm.new.list
951 | config.securityinspection.common.alarm.new.remove
952 | config.securityinspection.common.init
953 | config.securityinspection.common.probe
954 | config.securityinspection.common.probe.add
955 | config.securityinspection.common.probe.modify
956 | config.securityinspection.common.probe.remove
957 | config.securityinspection.common.probe.show
958 | config.securityinspection.common.show
959 | config.securityinspection.common.stateful
960 | config.securityinspection.config
961 | config.securityinspection.config.alarm
962 | config.securityinspection.config.alarm.list
963 | config.securityinspection.config.alarm.template
964 | config.securityinspection.config.copy
965 | config.securityinspection.config.default
966 | config.securityinspection.config.list
967 | config.securityinspection.config.protocol
968 | config.securityinspection.config.show
969 | config.securityinspection.config.update
970 | config.slot
971 | config.slot.activate
972 | config.slot.copy
973 | config.slot.default
974 | config.slot.download
975 | config.slot.list
976 | config.slot.remove
977 | config.slot.state
978 | config.slot.update
979 | config.slot.upload
980 | config.smcrouting
981 | config.smcrouting.activate
982 | config.smcrouting.default
983 | config.smcrouting.route
984 | config.smcrouting.route.add
985 | config.smcrouting.route.ipv6
986 | config.smcrouting.route.ipv6.add
987 | config.smcrouting.route.ipv6.move
988 | config.smcrouting.route.ipv6.remove
989 | config.smcrouting.route.ipv6.show
990 | config.smcrouting.route.ipv6.update
991 | config.smcrouting.route.move
992 | config.smcrouting.route.remove
993 | config.smcrouting.route.show
994 | config.smcrouting.route.update
995 | config.smcrouting.show
996 | config.smcrouting.update
997 | config.snmp
998 | config.snmp.access
999 | config.snmp.access.community
1000 | config.snmp.access.userv3
1001 | config.snmp.activate
1002 | config.snmp.show
1003 | config.snmp.state
1004 | config.snmp.system
1005 | config.snmp.trap
1006 | config.snmp.trap.auth
1007 | config.snmp.trap.v1
1008 | config.snmp.trap.v1.add
1009 | config.snmp.trap.v1.modify
1010 | config.snmp.trap.v1.remove
1011 | config.snmp.trap.v1.show
1012 | config.snmp.trap.v2
1013 | config.snmp.trap.v2.add
1014 | config.snmp.trap.v2.modify
1015 | config.snmp.trap.v2.remove
1016 | config.snmp.trap.v2.show
1017 | config.snmp.trap.v3
1018 | config.snmp.trap.v3.add
1019 | config.snmp.trap.v3.modify
1020 | config.snmp.trap.v3.remove
1021 | config.snmp.trap.v3.show
1022 | config.snmp.version
1023 | config.sslfiltering
1024 | config.sslfiltering.activate
1025 | config.sslfiltering.copy
1026 | config.sslfiltering.default
1027 | config.sslfiltering.list
1028 | config.sslfiltering.rule
1029 | config.sslfiltering.rule.insert
1030 | config.sslfiltering.rule.move
1031 | config.sslfiltering.rule.remove
1032 | config.sslfiltering.rule.show
1033 | config.sslfiltering.rule.update
1034 | config.sslfiltering.update
1035 | config.status
1036 | config.status.check
1037 | config.status.remove
1038 | config.status.show
1039 | config.status.validate
1040 | config.sysevent
1041 | config.sysevent.activate
1042 | config.sysevent.default
1043 | config.sysevent.modify
1044 | config.sysevent.show
1045 | config.upload
1046 | config.urlfiltering
1047 | config.urlfiltering.activate
1048 | config.urlfiltering.blockpage
1049 | config.urlfiltering.blockpage.default
1050 | config.urlfiltering.blockpage.list
1051 | config.urlfiltering.blockpage.update
1052 | config.urlfiltering.copy
1053 | config.urlfiltering.default
1054 | config.urlfiltering.list
1055 | config.urlfiltering.rule
1056 | config.urlfiltering.rule.insert
1057 | config.urlfiltering.rule.move
1058 | config.urlfiltering.rule.remove
1059 | config.urlfiltering.rule.show
1060 | config.urlfiltering.rule.update
1061 | config.urlfiltering.update
1062 | config.webadmin
1063 | config.webadmin.access
1064 | config.webadmin.access.add
1065 | config.webadmin.access.remove
1066 | config.webadmin.access.show
1067 | config.webadmin.access.sslonly
1068 | config.webadmin.activate
1069 | config.webadmin.adminaccount
1070 | config.webadmin.bruteforce
1071 | config.webadmin.bruteforce.nbattempts
1072 | config.webadmin.bruteforce.nbbruteforceentries
1073 | config.webadmin.bruteforce.state
1074 | config.webadmin.bruteforce.time
1075 | config.webadmin.bruteforce.triestime
1076 | config.webadmin.idle
1077 | config.webadmin.port
1078 | config.webadmin.show
1079 | config.webadmin.state
1080 | config.wifi
1081 | config.wifi.activate
1082 | config.wifi.list
1083 | config.wifi.list.channels
1084 | config.wifi.list.countrycodes
1085 | config.wifi.show
1086 | config.wifi.update
1087 | config.xvpn
1088 | config.xvpn.access
1089 | config.xvpn.activate
1090 | config.xvpn.advanced
1091 | config.xvpn.profile
1092 | config.xvpn.profile.activate
1093 | config.xvpn.profile.create
1094 | config.xvpn.profile.list
1095 | config.xvpn.profile.remove
1096 | config.xvpn.profile.show
1097 | config.xvpn.profile.update
1098 | config.xvpn.server
1099 | config.xvpn.server.http
1100 | config.xvpn.server.http.add
1101 | config.xvpn.server.http.alias
1102 | config.xvpn.server.http.alias.add
1103 | config.xvpn.server.http.alias.remove
1104 | config.xvpn.server.http.remove
1105 | config.xvpn.server.http.state
1106 | config.xvpn.server.http.update
1107 | config.xvpn.server.other
1108 | config.xvpn.server.other.add
1109 | config.xvpn.server.other.remove
1110 | config.xvpn.server.other.state
1111 | config.xvpn.server.other.update
1112 | config.xvpn.show
1113 | excluded
1114 | global
1115 | globaladmin
1116 | globaladmin.getinfos
1117 | globaladmin.getstatus
1118 | ha
1119 | ha.checksync
1120 | ha.cluster
1121 | ha.cluster.activate
1122 | ha.cluster.add
1123 | ha.cluster.list
1124 | ha.cluster.remove
1125 | ha.cluster.show
1126 | ha.cluster.update
1127 | ha.halt
1128 | ha.info
1129 | ha.reboot
1130 | ha.remote
1131 | ha.remote.haclusterremove
1132 | ha.remote.hainfo
1133 | ha.setmode
1134 | ha.sync
1135 | help
1136 | id1
1137 | id2
1138 | included
1139 | issuer
1140 | list
1141 | log
1142 | log.clear
1143 | log.datetoline
1144 | log.downlimit
1145 | log.download
1146 | log.info
1147 | log.property
1148 | log.search
1149 | log.search.get
1150 | log.search.jump
1151 | log.search.new
1152 | log.search.next
1153 | log.search.previous
1154 | log.search.resume
1155 | log.search.stop
1156 | modify
1157 | monitor
1158 | monitor.addresslist
1159 | monitor.addresslist.add
1160 | monitor.addresslist.delete
1161 | monitor.addresslist.show
1162 | monitor.agg
1163 | monitor.alarm
1164 | monitor.alarm.get
1165 | monitor.antivirus
1166 | monitor.autobackup
1167 | monitor.autoupdate
1168 | monitor.bypass
1169 | monitor.connection
1170 | monitor.cryptocard
1171 | monitor.dhcp
1172 | monitor.fan
1173 | monitor.filter
1174 | monitor.filtertable
1175 | monitor.filtertable.show
1176 | monitor.flush
1177 | monitor.flush.addresslist
1178 | monitor.flush.hostrep
1179 | monitor.flush.info
1180 | monitor.flush.pvm
1181 | monitor.flush.rulematch
1182 | monitor.flush.sa
1183 | monitor.flush.stat
1184 | monitor.flush.state
1185 | monitor.flush.user
1186 | monitor.fwadmin
1187 | monitor.getsa
1188 | monitor.getspd
1189 | monitor.gprs
1190 | monitor.health
1191 | monitor.host
1192 | monitor.hostrep
1193 | monitor.interface
1194 | monitor.ipgeoloc
1195 | monitor.iprep
1196 | monitor.log
1197 | monitor.openvpn
1198 | monitor.openvpn.list
1199 | monitor.openvpn.remove
1200 | monitor.policy
1201 | monitor.power
1202 | monitor.proxycache
1203 | monitor.pvm
1204 | monitor.pvm.force
1205 | monitor.pvm.force.check
1206 | monitor.pvm.force.list
1207 | monitor.pvm.force.set
1208 | monitor.pvm.host
1209 | monitor.pvm.hostbyos
1210 | monitor.pvm.hostbyproduct
1211 | monitor.pvm.hostbypvmid
1212 | monitor.pvm.hostbyservice
1213 | monitor.pvm.hostdata
1214 | monitor.pvm.info
1215 | monitor.pvm.os
1216 | monitor.pvm.product
1217 | monitor.pvm.service
1218 | monitor.pvm.stat
1219 | monitor.pvm.vuln
1220 | monitor.qos
1221 | monitor.raid
1222 | monitor.revrt
1223 | monitor.route
1224 | monitor.sandboxing
1225 | monitor.sandboxing.misclass
1226 | monitor.services
1227 | monitor.smart
1228 | monitor.stat
1229 | monitor.system
1230 | monitor.thind
1231 | monitor.user
1232 | nop
1233 | pki
1234 | pki.ca
1235 | pki.ca.check
1236 | pki.ca.checkcrl
1237 | pki.ca.checkcrl.add
1238 | pki.ca.checkcrl.remove
1239 | pki.ca.checkcrl.show
1240 | pki.ca.checkcrl.update
1241 | pki.ca.config
1242 | pki.ca.config.crldp
1243 | pki.ca.config.crldp.add
1244 | pki.ca.config.crldp.remove
1245 | pki.ca.config.crldp.show
1246 | pki.ca.config.show
1247 | pki.ca.config.update
1248 | pki.ca.create
1249 | pki.ca.get
1250 | pki.ca.list
1251 | pki.ca.publish
1252 | pki.ca.purge
1253 | pki.ca.rename
1254 | pki.ca.revoke
1255 | pki.ca.show
1256 | pki.certificate
1257 | pki.certificate.check
1258 | pki.certificate.comment
1259 | pki.certificate.create
1260 | pki.certificate.dropkey
1261 | pki.certificate.get
1262 | pki.certificate.list
1263 | pki.certificate.publish
1264 | pki.certificate.rename
1265 | pki.certificate.revoke
1266 | pki.certificate.show
1267 | pki.config
1268 | pki.config.show
1269 | pki.config.update
1270 | pki.crl
1271 | pki.crl.create
1272 | pki.crl.get
1273 | pki.crl.publish
1274 | pki.crl.remove
1275 | pki.crl.show
1276 | pki.import
1277 | pki.request
1278 | pki.request.create
1279 | pki.request.get
1280 | pki.request.list
1281 | pki.request.remove
1282 | pki.request.show
1283 | pki.request.sign
1284 | pki.scep
1285 | pki.scep.check
1286 | pki.scep.query
1287 | pki.search
1288 | quit
1289 | report
1290 | report.get
1291 | report.get.day
1292 | report.get.last30days
1293 | report.get.last7days
1294 | report.get.lasthour
1295 | report.reset
1296 | server
1297 | subject
1298 | system
1299 | system.backup
1300 | system.bypass
1301 | system.bypass.activate
1302 | system.bypass.config
1303 | system.bypass.rearm
1304 | system.clone
1305 | system.date
1306 | system.defaultconfig
1307 | system.fwadmin
1308 | system.halt
1309 | system.ident
1310 | system.information
1311 | system.initialize
1312 | system.language
1313 | system.led
1314 | system.licence
1315 | system.licence.dump
1316 | system.licence.updater
1317 | system.licence.updater.config
1318 | system.licence.updater.diff
1319 | system.licence.updater.get
1320 | system.licence.updater.install
1321 | system.licence.updater.show
1322 | system.licence.upload
1323 | system.logdisk
1324 | system.logdisk.format
1325 | system.logdisk.list
1326 | system.logdisk.select
1327 | system.logdisk.state
1328 | system.nslookup
1329 | system.ping
1330 | system.property
1331 | system.reboot
1332 | system.register
1333 | system.right
1334 | system.right.activate
1335 | system.right.insert
1336 | system.right.list
1337 | system.right.move
1338 | system.right.remove
1339 | system.right.ticket
1340 | system.right.ticket.acquire
1341 | system.right.ticket.activate
1342 | system.right.ticket.delete
1343 | system.right.ticket.list
1344 | system.right.ticket.new
1345 | system.right.ticket.release
1346 | system.right.update
1347 | system.session
1348 | system.setboot
1349 | system.setbranch
1350 | system.status
1351 | system.timezone
1352 | system.timezone.get
1353 | system.timezone.list
1354 | system.timezone.set
1355 | system.traceroute
1356 | system.update
1357 | system.update.activate
1358 | system.update.check
1359 | system.update.load
1360 | system.update.result
1361 | system.update.status
1362 | system.update.upload
1363 | system.watchdog
1364 | user
1365 | user.access
1366 | user.access.activate
1367 | user.access.default
1368 | user.access.default.show
1369 | user.access.default.update
1370 | user.access.insert
1371 | user.access.list
1372 | user.access.move
1373 | user.access.remove
1374 | user.access.right
1375 | user.access.right.insert
1376 | user.access.right.list
1377 | user.access.right.move
1378 | user.access.right.remove
1379 | user.access.right.update
1380 | user.access.update
1381 | user.certificate
1382 | user.check
1383 | user.create
1384 | user.group
1385 | user.group.addto
1386 | user.group.adduser
1387 | user.group.check
1388 | user.group.create
1389 | user.group.deluser
1390 | user.group.description
1391 | user.group.list
1392 | user.group.new
1393 | user.group.remove
1394 | user.group.removefrom
1395 | user.group.show
1396 | user.list
1397 | user.password
1398 | user.remove
1399 | user.request
1400 | user.request.approved
1401 | user.request.format
1402 | user.request.format.set
1403 | user.request.format.show
1404 | user.request.list
1405 | user.request.remove
1406 | user.request.sendmail
1407 | user.request.show
1408 | user.request.update
1409 | user.search
1410 | user.show
1411 | user.update
1412 | user.voucher
1413 | user.voucher.account
1414 | user.voucher.account.create
1415 | user.voucher.account.delete
1416 | user.voucher.account.list
1417 | user.voucher.account.resetpassword
1418 | user.voucher.account.status
1419 | user.voucher.account.update
1420 | version
1421 |
--------------------------------------------------------------------------------
/stormshield/sns/configparser.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | """
4 | stormshield.sns.configparser
5 |
6 | This module handles SNS API responses and extract section/token/values
7 | in ini/section format.
8 | """
9 |
10 | import sys
11 | import re
12 | from shlex import shlex
13 | from requests.structures import CaseInsensitiveDict
14 |
15 | def unquote(value):
16 | """ remove quotes if needed """
17 | if isinstance(value, str) and len(value) > 1 and value[0] == '"' and value[-1] == '"':
18 | return value[1:-1]
19 | return value
20 |
21 | def serialize(data):
22 | if type(data) is CaseInsensitiveDict:
23 | res = {}
24 | for (k, v) in data.items():
25 | res[k] = serialize(v)
26 | return res
27 | elif type(data) is list:
28 | res = []
29 | for v in data:
30 | res.append(serialize(v))
31 | return res
32 | else:
33 | return data
34 |
35 |
36 | class ConfigParser:
37 | """ A class to parse section format from SNS API responses """
38 |
39 | SERVERD_HEAD_RE = re.compile(r'^\d{3} code=.* msg=.* format="(.*?)"')
40 | SERVERD_TAIL_RE = re.compile(r'^\d{3} code=.*? msg=.*?')
41 | SECTION_RE = re.compile(r'^\s*\[\s*(.+?)\s*\]\s*$')
42 | EMPTY_RE = re.compile(r'^\s*$')
43 | TOKEN_VALUE_RE = re.compile(r'^(.*?)=(.*)$')
44 |
45 | def __init__(self, text):
46 | """ load a section from text """
47 |
48 | self.data = CaseInsensitiveDict()
49 | self.format = None
50 |
51 | lines = text.splitlines()
52 |
53 | # strip serverd headers if needed
54 | match = self.SERVERD_HEAD_RE.match(lines[0])
55 | if match:
56 | del lines[0]
57 | self.format = match.group(1)
58 | if self.SERVERD_TAIL_RE.match(lines[-1]):
59 | del lines[-1]
60 |
61 | text = "\n".join(lines)
62 |
63 | if self.format == 'raw' or self.format == 'xml':
64 | # plain data, no parsing
65 | self.data = text
66 | return
67 |
68 | section = "Result" # default section
69 | for line in text.splitlines():
70 |
71 | # comment
72 | if line.startswith('#'):
73 | continue
74 |
75 | # empty lines
76 | if self.EMPTY_RE.match(line):
77 | continue
78 |
79 | # section header
80 | match = self.SECTION_RE.match(line)
81 | if match:
82 | section = match.group(1)
83 | if self.format == 'section':
84 | self.data[section] = CaseInsensitiveDict()
85 | else:
86 | self.data[section] = []
87 | continue
88 |
89 | if self.format == "list":
90 | self.data[section].append(line)
91 | elif self.format == "section_line":
92 | # fix encoding for python2
93 | if sys.version_info[0] < 3:
94 | line = line.encode('utf-8')
95 | # parse token=value token2=value2
96 | lexer = shlex(line, posix=True)
97 | lexer.wordchars += "=.-*:,/@'()"
98 | lexer.quotes = '"'
99 | parsed = {}
100 | try:
101 | for word in lexer:
102 | # ignore anything else than token=value
103 | if '=' in word:
104 | token, value = word.split("=", 1)
105 | parsed[token] = value
106 | except Exception as e:
107 | print("Can't parse line:\n" + line + "\n")
108 | print(e)
109 | raise(e)
110 | self.data[section].append(parsed)
111 | else:
112 | # section
113 | (token, value) = line.split("=", 1)
114 | self.data[section][token] = unquote(value)
115 |
116 |
117 | def get(self, section, token=None, line=None, default=None):
118 | """ get the value of a token or a plain line from the current section """
119 |
120 | if section not in self.data:
121 | value = default
122 |
123 | elif token is not None:
124 | # token/value mode
125 |
126 | if token not in self.data[section]:
127 | value = default
128 | else:
129 | value = unquote(self.data[section][token])
130 | elif line is None:
131 | # return all tokens/lines form section
132 | if self.format == "section":
133 | value = self.data[section]
134 | elif section not in self.data:
135 | value = []
136 | else:
137 | value = self.data[section]
138 | else:
139 | if line < 1:
140 | value = default
141 | elif section not in self.data:
142 | value = default
143 | elif len(self.data[section]) < line:
144 | value = default
145 | else:
146 | value = self.data[section][line-1]
147 |
148 | return value
149 |
150 | def serialize_data(self):
151 | """ return serializable output parsed data """
152 |
153 | return serialize(self.data)
154 |
--------------------------------------------------------------------------------
/stormshield/sns/crc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | """
4 | stormshield.sns.crc
5 |
6 | This module implements SNS crc32 functions.
7 | """
8 |
9 |
10 |
11 | CRC32_init = 0xffffffff
12 |
13 | CRCTAB = [
14 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
15 | 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
16 | 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
17 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
18 | 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
19 | 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
20 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
21 | 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
22 | 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
23 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
24 | 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
25 | 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
26 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
27 | 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
28 | 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
29 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
30 | 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
31 | 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
32 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
33 | 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
34 | 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
35 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
36 | 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
37 | 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
38 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
39 | 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
40 | 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
41 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
42 | 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
43 | 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
44 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
45 | 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
46 | 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
47 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
48 | 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
49 | 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
50 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
51 | 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
52 | 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
53 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
54 | 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
55 | 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
56 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
57 | 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
58 | 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
59 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
60 | 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
61 | 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
62 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
63 | 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
64 | 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
65 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
66 | 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
67 | 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
68 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
69 | 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
70 | 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
71 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
72 | 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
73 | 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
74 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
75 | 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
76 | 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
77 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
78 | ]
79 |
80 |
81 |
82 | def compute_crc32(data):
83 | """ Returns the hex string of CRC value of DATA """
84 |
85 | # python2 convert str to bytes
86 | if type(data) == str:
87 | data = bytearray(data)
88 |
89 | n = len(data)
90 | crc = CRC32_init
91 |
92 | for i in range(0, n):
93 | crc = (crc >> 8) ^ CRCTAB[(crc ^ data[i]) & 0xff]
94 | return crc
95 |
96 |
97 | def update_crc32(data, crc):
98 | """ Incremental CRC, returns updated CRC. """
99 |
100 | # python2 convert str to bytes
101 | if type(data) == str:
102 | data = bytearray(data)
103 |
104 | n = len(data)
105 |
106 | for i in range(0, n):
107 | crc = (crc >> 8) ^ CRCTAB[(crc ^ data[i]) & 0xff]
108 |
109 | return crc
110 |
--------------------------------------------------------------------------------
/stormshield/sns/sslclient/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | stormshield.sns.sslclient
6 | ~~~~~~~~~~~~~~~~~~~~~~~~~
7 |
8 | This module contains SSLClient class to handle SNS API calls
9 | and Response class to handle API answers.
10 | """
11 |
12 | from __future__ import unicode_literals
13 | import os
14 | import ipaddress
15 | import base64
16 | import logging
17 | import re
18 | import platform
19 | import defusedxml.ElementTree as ElementTree
20 | from xml.etree import ElementTree as Et
21 | import ssl
22 | import requests
23 | from requests.adapters import HTTPAdapter, DEFAULT_POOLSIZE, DEFAULT_RETRIES, DEFAULT_POOLBLOCK
24 | from urllib3.poolmanager import PoolManager, proxy_from_url
25 | from requests.utils import get_auth_from_url
26 | from requests.exceptions import InvalidSchema
27 | import requests.compat
28 | from requests_toolbelt.multipart.encoder import MultipartEncoder
29 | import urllib3
30 | try:
31 | from urllib3.contrib.socks import SOCKSProxyManager
32 | except ImportError:
33 | def SOCKSProxyManager(*args, **kwargs):
34 | raise InvalidSchema("Missing dependencies for SOCKS support.")
35 |
36 | from stormshield.sns.configparser import ConfigParser
37 | import stormshield.sns.crc as snscrc
38 | from packaging import version
39 |
40 | from .__version__ import __version__
41 |
42 | URLLIB3V2 = version.parse(urllib3.__version__) >= version.parse('2.0.0')
43 |
44 | #disable ssl warnings, we have --sslverify* for that
45 | requests.packages.urllib3.disable_warnings(
46 | requests.packages.urllib3.exceptions.InsecureRequestWarning)
47 | try:
48 | requests.packages.urllib3.disable_warnings(
49 | requests.packages.urllib3.exceptions.SubjectAltNameWarning)
50 | except AttributeError:
51 | # urllib3 v2 doesn't have the exception anymore
52 | pass
53 | #disable http warning 'Received response with both Content-Length and Transfer-Encoding set'
54 | logging.getLogger(requests.packages.urllib3.__name__).setLevel(logging.ERROR)
55 |
56 | class HostNameAdapter(HTTPAdapter):
57 | """ HTTP adapter to disable strict ssl host name verification or check hostname against common name """
58 |
59 | def __init__(self, host=None):
60 | self.host = host
61 | super().__init__()
62 |
63 | def init_poolmanager(self, connections, maxsize, block=False, **pool_kwargs):
64 |
65 | if URLLIB3V2:
66 | context = ssl.create_default_context()
67 | context.hostname_checks_common_name = True # use CN field for factory Stormshield certificates
68 | context.check_hostname = False # check is done with assert_hostname
69 |
70 | self.poolmanager = PoolManager(num_pools=connections,
71 | maxsize=maxsize,
72 | block=block,
73 | assert_hostname=self.host,
74 | ssl_context=context,
75 | **pool_kwargs)
76 | else:
77 | self.poolmanager = PoolManager(num_pools=connections,
78 | maxsize=maxsize,
79 | block=block,
80 | assert_hostname=False,
81 | **pool_kwargs)
82 |
83 | def proxy_manager_for(self, proxy, **proxy_kwargs):
84 | if proxy in self.proxy_manager:
85 | manager = self.proxy_manager[proxy]
86 | elif proxy.lower().startswith('socks'):
87 | username, password = get_auth_from_url(proxy)
88 |
89 | if URLLIB3V2:
90 | context = ssl.create_default_context()
91 | context.hostname_checks_common_name = True
92 | context.check_hostname = False
93 |
94 | manager = self.proxy_manager[proxy] = SOCKSProxyManager(
95 | proxy,
96 | username=username,
97 | password=password,
98 | num_pools=self._pool_connections,
99 | maxsize=self._pool_maxsize,
100 | block=self._pool_block,
101 | assert_hostname=self.host,
102 | ssl_context=context,
103 | **proxy_kwargs
104 | )
105 | else:
106 | manager = self.proxy_manager[proxy] = SOCKSProxyManager(
107 | proxy,
108 | username=username,
109 | password=password,
110 | num_pools=self._pool_connections,
111 | maxsize=self._pool_maxsize,
112 | block=self._pool_block,
113 | assert_hostname=False,
114 | **proxy_kwargs
115 | )
116 | else:
117 | proxy_headers = self.proxy_headers(proxy)
118 |
119 | if URLLIB3V2:
120 | context = ssl.create_default_context()
121 | context.hostname_checks_common_name = True
122 | context.check_hostname = False
123 |
124 | manager = self.proxy_manager[proxy] = proxy_from_url(
125 | proxy,
126 | proxy_headers=proxy_headers,
127 | num_pools=self._pool_connections,
128 | maxsize=self._pool_maxsize,
129 | block=self._pool_block,
130 | assert_hostname=self.host,
131 | ssl_context=context,
132 | **proxy_kwargs)
133 | else:
134 | manager = self.proxy_manager[proxy] = proxy_from_url(
135 | proxy,
136 | proxy_headers=proxy_headers,
137 | num_pools=self._pool_connections,
138 | maxsize=self._pool_maxsize,
139 | block=self._pool_block,
140 | assert_hostname=False,
141 | **proxy_kwargs)
142 |
143 | return manager
144 |
145 | class DNSResolverHTTPSAdapter(HTTPAdapter):
146 | """ HTTP adapter to check peer common_name with provided host name """
147 |
148 | def __init__(self, common_name, host, pool_connections=DEFAULT_POOLSIZE,
149 | pool_maxsize=DEFAULT_POOLSIZE, max_retries=DEFAULT_RETRIES,
150 | pool_block=DEFAULT_POOLBLOCK):
151 | self.__common_name = common_name
152 | self.__host = host
153 |
154 | self.__is_stormshield_cert = True
155 | if re.search(r"\.", self.__common_name):
156 | self.__is_stormshield_cert = False
157 |
158 | super(DNSResolverHTTPSAdapter, self).__init__(pool_connections=pool_connections,
159 | pool_maxsize=pool_maxsize,
160 | max_retries=max_retries,
161 | pool_block=pool_block)
162 |
163 | def init_poolmanager(self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool_kwargs):
164 | pool_kwargs['assert_hostname'] = self.__common_name
165 | if URLLIB3V2 and self.__is_stormshield_cert:
166 | context = ssl.create_default_context()
167 | context.hostname_checks_common_name = True # use CN field for factory Stormshield certificates
168 | context.check_hostname = False # check is done with assert_hostname
169 | pool_kwargs["ssl_context"] = context
170 | super(DNSResolverHTTPSAdapter, self).init_poolmanager(connections,
171 | maxsize,
172 | block=block,
173 | **pool_kwargs)
174 |
175 | class Response():
176 | """ :class:`Response ` object contains the SNS API response to a request """
177 |
178 | def __init__(self, code=None, ret=0, msg=None, output=None, xml=None):
179 | self.code = code
180 | self.ret = ret
181 | self.msg = msg
182 | self.output = output
183 | self.xml = xml
184 |
185 | self.parser = ConfigParser(output)
186 | self.data = self.parser.data
187 | self.format = self.parser.format
188 |
189 | def __repr__(self):
190 | return self.output
191 |
192 | def __bool__(self):
193 | """ Returns True if :attr:`ret` is OK or WARNING. """
194 | return self.ret >= 100 and self.ret < 200
195 |
196 | def quote(value):
197 | """ Quote value if needed """
198 | try:
199 | if value and (type(value) == str or type(value) == unicode) and ' ' in value:
200 | return '"' + value + '"'
201 | except:
202 | # in python3 unicode class doesn't exists
203 | pass
204 | return value
205 |
206 | def format_output(output):
207 | """ Format command output in ini/section or text format"""
208 | nws_node = ElementTree.fromstring(output)
209 | serverd_node = nws_node[0]
210 | ini = '{} code={} msg="{}"'.format(serverd_node.get('ret'),
211 | serverd_node.get('code'),
212 | serverd_node.get('msg'))
213 | if len(list(nws_node)) > 1:
214 | data_node = serverd_node[0]
215 | node_format = data_node.get('format')
216 | ini += ' format="{}"\n'.format(node_format)
217 | if node_format == 'raw':
218 | if data_node.text:
219 | ini += data_node.text
220 | elif node_format == 'section':
221 | for section_node in data_node:
222 | ini += '[{}]\n'.format(section_node.get('title'))
223 | for key_node in section_node:
224 | ini += '{}={}\n'.format(key_node.get('name'),
225 | quote(key_node.get('value')))
226 | elif node_format == 'section_line':
227 | for section_node in data_node:
228 | ini += '[{}]\n'.format(section_node.get('title'))
229 | for line_node in section_node:
230 | tokens = []
231 | for key_node in line_node:
232 | tokens.append('{}={}'.format(key_node.get('name'),
233 | quote(key_node.get('value'))))
234 | ini += " ".join(tokens) + "\n"
235 | elif node_format == 'list':
236 | for section_node in data_node:
237 | ini += '[{}]\n'.format(section_node.get('title'))
238 | for line_node in section_node:
239 | ini += "{}\n".format(line_node.text)
240 | elif node_format == 'xml':
241 | # display xml data node
242 | ini += Et.tostring(data_node).decode() + "\n"
243 | serverd_node = nws_node[1]
244 | ini += '{} code={} msg="{}"'.format(serverd_node.get('ret'),
245 | serverd_node.get('code'),
246 | serverd_node.get('msg'))
247 | return ini
248 |
249 | class MissingHost(ValueError):
250 | """ The remote host is missing """
251 |
252 | class MissingAuth(ValueError):
253 | """ password or user certificate is missing """
254 |
255 | class MissingCABundle(ValueError):
256 | """ The certificate authority bundle is missing """
257 |
258 | class TOTPNeededError(Exception):
259 | """ Time-base one time password needed """
260 |
261 | class AuthenticationError(Exception):
262 | """ authentication failed """
263 |
264 | class ServerError(Exception):
265 | """ NWS server error """
266 |
267 | class FileError(Exception):
268 | """ file access error """
269 |
270 | class SSLClient:
271 | """SSL client to SNS configuration API """
272 |
273 | SSL_SERVERD_OK = 100
274 | SSL_SERVERD_REQUEST_ERROR = 200
275 | SSL_SERVERD_UNKNOWN_COMMAND = 201
276 | SSL_SERVERD_ERROR_COMMAND = 202
277 | SSL_SERVERD_INVALID_SESSION = 203
278 | SSL_SERVERD_EXPIRED_SESSION = 204
279 | SSL_SERVERD_AUTH_ERROR = 205
280 | SSL_SERVERD_PENDING_TRANSFER = 206
281 | SSL_SERVERD_PENDING_UPLOAD = 207
282 | SSL_SERVERD_OVERHEAT = 500
283 | SSL_SERVERD_UNREACHABLE = 501
284 | SSL_SERVERD_DISCONNECTED = 502
285 | SSL_SERVERD_INTERNAL_ERROR = 900
286 |
287 | SSL_SERVERD_MSG = {
288 | SSL_SERVERD_REQUEST_ERROR: "Request error",
289 | SSL_SERVERD_UNKNOWN_COMMAND: "Unknown command",
290 | SSL_SERVERD_ERROR_COMMAND: "Command error",
291 | SSL_SERVERD_INVALID_SESSION: "Invalid session",
292 | SSL_SERVERD_EXPIRED_SESSION: "Expired session",
293 | SSL_SERVERD_AUTH_ERROR: "Authentication error",
294 | SSL_SERVERD_PENDING_TRANSFER: "Pending transfer",
295 | SSL_SERVERD_PENDING_UPLOAD: "Upload pending",
296 | SSL_SERVERD_OVERHEAT: "Server overheat",
297 | SSL_SERVERD_UNREACHABLE: "Server unreachable",
298 | SSL_SERVERD_DISCONNECTED: "Server disconnected",
299 | SSL_SERVERD_INTERNAL_ERROR: "Internal error"
300 | }
301 |
302 | SRV_RET_OK = 100
303 | SRV_RET_DOWNLOAD = 101
304 | SRV_RET_UPLOAD = 102
305 | SRV_RET_LASTCMD = 103
306 | SRV_RET_MUSTREBOOT = 104
307 | SRV_RET_WARNING = 110
308 | SRV_RET_MULTIWARN = 111
309 | SRV_RET_COMMAND = 200
310 | SRV_RET_MULTILINE = 201
311 | SRV_RET_AUTHFAILED = 202
312 | SRV_RET_IDLE = 203
313 | SRV_RET_AUTHLIMIT = 204
314 | SRV_RET_AUTHLEVEL = 205
315 | SRV_RET_LICENCE = 206
316 |
317 | SRV_RET_MSG = {
318 | SRV_RET_OK: 'Command successful',
319 | SRV_RET_DOWNLOAD: 'Command successful, download follow',
320 | SRV_RET_UPLOAD: 'Command successful, upload follow',
321 | SRV_RET_LASTCMD: 'Command successful, you will be disconnected',
322 | SRV_RET_MUSTREBOOT: 'Command successful, but reboot needed',
323 | SRV_RET_WARNING: 'Command successful, but warning',
324 | SRV_RET_MULTIWARN: 'Command successful, but multiple warnings',
325 | SRV_RET_COMMAND: 'Command error',
326 | SRV_RET_MULTILINE: 'Return error message on many lines',
327 | SRV_RET_AUTHFAILED: 'Authentication failed',
328 | SRV_RET_IDLE: 'Client is idle, disconnecting',
329 | SRV_RET_AUTHLIMIT: 'Maximum number of authentication user reached for that level',
330 | SRV_RET_AUTHLEVEL: 'Not enough privilege',
331 | SRV_RET_LICENCE: 'Licence restriction'
332 | }
333 |
334 | SERVERD_WAIT_DOWNLOAD = "00a01c00"
335 | SERVERD_WAIT_UPLOAD = "00a00300"
336 | AUTH_SUCCESS = "AUTH_SUCCESS"
337 | AUTH_FAILED = "AUTH_FAILED"
338 | NEED_TOTP_AUTH = "NEED_TOTP_AUTH"
339 | ERR_BRUTEFORCE = "ERR_BRUTEFORCE"
340 |
341 | fileregexp = re.compile(r'^(?P.+?)\s*[<>]\s*(?!.*\")(?P.*?)$')
342 |
343 | CHUNK_SIZE = 10240 # bytes
344 |
345 | def __init__(self, user='admin', password=None, totp=None, host=None, ip=None, port=443, cabundle=None,
346 | sslverifypeer=True, sslverifyhost=True, credentials=None,
347 | usercert=None, autoconnect=True, proxy=None, timeout=None):
348 | """:class:`SSLclient ` constructor.
349 |
350 | :param user: Optional user name.
351 | :param password: Optional password.
352 | :param totp: Optional time-based one time password.
353 | :param host: hostname to connect or certificate common name (appliance serial).
354 | :param ip: Optional ip address to connect.
355 | :param port: Optional port number.
356 | :param cabundle: Optional certificat authorities bundle file in PEM format.
357 | :param sslverifypeer: Optional boolean to verify remote certificate authority.
358 | :param sslverifyhost: Optional boolean to verify remote certificate common name.
359 | :param credentials: Optional list of requested privileges.
360 | :param usercert: Optional user certificate.
361 | :param autoconnect: Connect to the appliance at initialization
362 | :param proxy: https proxy url (socks5://user:pass@host:port http://user:password@host/)
363 | :param timeout: connection and read timeout in seconds
364 | """
365 |
366 | self.user = user
367 | self.password = password
368 | self.totp = totp
369 | self.host = host
370 | self.ip = ip
371 | self.port = port
372 | self.cabundle = cabundle
373 | self.app = 'sslclient'
374 | self.sslverifypeer = sslverifypeer
375 | self.sslverifyhost = sslverifyhost
376 | self.credentials = credentials
377 | self.usercert = usercert
378 | self.sessionid = ""
379 | self.protocol = ""
380 | self.sessionlevel = ""
381 | self.dl_size = 0
382 | self.dl_crc = ""
383 | self.autoconnect = autoconnect
384 | self.proxy = proxy
385 | self.conn_options = {}
386 |
387 | if host is None:
388 | raise MissingHost("Host parameter must be provided")
389 | if password is None and usercert is None:
390 | raise MissingAuth("Password parameter must be provided")
391 | if password is None and totp is not None:
392 | raise MissingAuth("Password parameter must be provided when totp parameter is provided")
393 | if usercert is not None and not os.path.isfile(usercert):
394 | raise MissingAuth("User certificate not found")
395 | if cabundle is None:
396 | # use default cabundle
397 | self.cabundle = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", 'bundle.ca'))
398 | if not os.path.isfile(self.cabundle):
399 | raise MissingCABundle("Certificate authority bunble not found")
400 |
401 | #test ipv6 address
402 | try:
403 | ipaddress.IPv6Address(self.host)
404 | urlhost = "[{}]".format(self.host)
405 | except ipaddress.AddressValueError:
406 | urlhost = self.host
407 |
408 | self.baseurl = 'https://' + urlhost + ':' + str(self.port)
409 |
410 | self.headers = {
411 | 'user-agent': 'stormshield.sns.sslclient/{} ({})'.format(
412 | __version__, platform.platform())
413 | }
414 |
415 | self.session = requests.Session()
416 | if self.sslverifypeer:
417 | self.session.verify = self.cabundle
418 | else:
419 | self.session.verify = False
420 |
421 | if not self.sslverifyhost:
422 | if URLLIB3V2:
423 | self.session.mount(self.baseurl, HostNameAdapter(False))
424 | else:
425 | self.session.mount(self.baseurl, HostNameAdapter())
426 |
427 | if self.ip is not None:
428 | #test ipv6 address
429 | try:
430 | ipaddress.IPv6Address(self.ip)
431 | urlip = "[{}]".format(self.ip)
432 | except ipaddress.AddressValueError:
433 | urlip = self.ip
434 | self.baseurl = 'https://' + urlip + ':' + str(self.port)
435 | self.session.mount(self.baseurl.lower(), DNSResolverHTTPSAdapter(self.host, self.ip))
436 |
437 | if self.usercert is not None:
438 | self.session.cert = self.usercert
439 |
440 | if self.proxy:
441 | self.session.proxies = { "https": self.proxy}
442 |
443 | if timeout is not None:
444 | self.conn_options = { "timeout": timeout }
445 |
446 | self.logger = logging.getLogger()
447 |
448 | if self.autoconnect:
449 | self.connect()
450 |
451 | @staticmethod
452 | def get_completer():
453 | """ Get the path to the installed cmd.complete file """
454 | return os.path.normpath(os.path.join(os.path.dirname(__file__), "..", 'cmd.complete'))
455 |
456 | def connect(self):
457 | """ Connect to the server """
458 |
459 | self.logger.log(logging.INFO, 'Connecting to %s on port %d with user %s%s',
460 | self.host, self.port, self.user, " (proxy {})".format(self.proxy) if self.proxy else "")
461 |
462 | # 1. Authentication and get cookie
463 | if self.usercert is not None:
464 | # user cert authentication
465 | self.logger.log(logging.DEBUG, "Authentication with SSL certificate")
466 | request = self.session.get(
467 | self.baseurl + '/auth/admin.html?sslcert=1&app={}'.format(self.app),
468 | headers=self.headers, **self.conn_options)
469 | else:
470 | # password authentication
471 | self.logger.log(logging.DEBUG, "Authentication with user/password")
472 | data = { 'uid':base64.b64encode(self.user.encode('utf-8')),
473 | 'pswd':base64.b64encode(self.password.encode('utf-8')),
474 | 'app':self.app }
475 |
476 | if self.totp is not None:
477 | data['totp']=base64.b64encode(self.totp.encode('utf-8'))
478 |
479 | request = self.session.post(
480 | self.baseurl + '/auth/admin.html',
481 | data,
482 | headers=self.headers,
483 | **self.conn_options)
484 |
485 | self.logger.log(logging.DEBUG, request.text)
486 |
487 | try:
488 | nws_node = ElementTree.fromstring(request.content)
489 | msg = nws_node.attrib['msg']
490 | except (ElementTree.ParseError, KeyError):
491 | raise ServerError("Can't decode authentication result")
492 |
493 | if msg == self.ERR_BRUTEFORCE:
494 | nws_node = ElementTree.fromstring(request.content)
495 | delay = nws_node.attrib['delay']
496 | raise AuthenticationError("Brut force detected, try again after " + delay + " seconds.")
497 | if msg == self.NEED_TOTP_AUTH:
498 | raise TOTPNeededError("TOTP is needed")
499 | if msg != self.AUTH_SUCCESS:
500 | raise AuthenticationError("Authentication failed")
501 |
502 | # 2. Serverd session
503 | data = {'app': self.app, 'id': 0}
504 | if self.credentials is not None:
505 | data['reqlevel'] = self.credentials
506 | request = self.session.post(
507 | self.baseurl + '/api/auth/login',
508 | data=data,
509 | headers=self.headers,
510 | **self.conn_options)
511 |
512 | self.logger.log(logging.DEBUG, request.text)
513 |
514 | if request.status_code == requests.codes.OK:
515 | nws_node = ElementTree.fromstring(request.content)
516 | ret = int(nws_node.attrib['code'])
517 | msg = nws_node.attrib['msg']
518 |
519 | if ret != self.SSL_SERVERD_OK:
520 | raise ServerError("ERROR: {} {}".format(ret, msg))
521 |
522 | self.sessionid = nws_node.find('sessionid').text
523 | self.protocol = nws_node.find('protocol').text
524 | self.sessionlevel = nws_node.find('sessionlevel').text
525 |
526 | self.logger.log(logging.DEBUG, "Session ID: %s", self.sessionid)
527 | self.logger.log(logging.DEBUG, "Protocol: %s", self.protocol)
528 | self.logger.log(logging.DEBUG, "Session level: %s", self.sessionlevel)
529 |
530 | else:
531 | raise ServerError("can't get serverd session")
532 |
533 |
534 |
535 | def disconnect(self):
536 | """ Disconnect from the server """
537 |
538 | request = self.session.get(
539 | self.baseurl + '/api/auth/logout?sessionid=' + self.sessionid,
540 | headers=self.headers, **self.conn_options)
541 |
542 | if request.status_code == requests.codes.OK:
543 | self.logger.log(logging.INFO, 'Disconnected from %s', self.host)
544 | else:
545 | self.logger.log(logging.ERROR, 'Disconnect failed')
546 |
547 | self.session.close()
548 |
549 | def nws_parse(self, code):
550 | """ Parse server response """
551 |
552 | if code == self.SSL_SERVERD_OK:
553 | return
554 |
555 | if code == self.SSL_SERVERD_AUTH_ERROR:
556 | raise AuthenticationError(self.SSL_SERVERD_MSG[code])
557 | elif code in self.SSL_SERVERD_MSG:
558 | raise ServerError(self.SSL_SERVERD_MSG[code])
559 | else:
560 | raise ServerError("Unknown error")
561 |
562 | def send_command(self, command, **conn_options):
563 | """Execute a NSRPC command on the remote appliance.
564 |
565 | :param command: SNS API command. Files can be uploaded by adding '< filename'
566 | at the end of the command. Downloads are handled with '> filename'.
567 | :return: :class:`Response ` object
568 | :rtype: stormshield.sns.Response
569 | """
570 |
571 | # overload connection options
572 | for k in self.conn_options:
573 | if k not in conn_options:
574 | conn_options[k] = self.conn_options[k]
575 |
576 | filename = None
577 | result = self.fileregexp.match(command)
578 | if result:
579 | command = result.group('cmd')
580 | filename = result.group('file')
581 |
582 | request = self.session.get(
583 | self.baseurl + '/api/command?sessionid=' + self.sessionid +
584 | '&cmd=' + requests.compat.quote(command.encode('utf-8')), # manually done since we need %20 encoding
585 | headers=self.headers, **conn_options)
586 |
587 | self.logger.log(logging.DEBUG, request.text)
588 |
589 | if request.status_code == requests.codes.OK:
590 | nws_node = ElementTree.fromstring(request.content)
591 | code = int(nws_node.attrib['code'])
592 | self.nws_parse(code)
593 | serverd = nws_node[0]
594 |
595 | if serverd is not None:
596 | serverd_code = serverd.attrib['code']
597 | serverd_ret = int(serverd.attrib['ret'])
598 | serverd_msg = serverd.attrib['msg']
599 |
600 | response = Response(ret=serverd_ret,
601 | code=serverd_code,
602 | msg=serverd_msg,
603 | output=format_output(request.content),
604 | xml=request.text)
605 |
606 | #multiline answer get the final code
607 | if len(list(nws_node)) > 1:
608 | response.code = nws_node[1].get('code')
609 | response.msg = nws_node[1].get('msg')
610 | response.ret = int(nws_node[1].get('ret'))
611 |
612 | if serverd_code == self.SERVERD_WAIT_UPLOAD:
613 | if filename:
614 | return self.upload(filename)
615 | return response
616 |
617 | if serverd_code == self.SERVERD_WAIT_DOWNLOAD:
618 | data = serverd.find('data')
619 | # keep size and crc for further verification
620 | if data.get('format') == 'section':
621 | #
622 | key = data.find('section').find('key')
623 | values = key.get('value').split(',')
624 | self.dl_size = int(values[2].split('=')[1])
625 | self.dl_crc = values[1].split('=')[1]
626 | else:
627 | # 439B8525096
628 | self.dl_size = int(data.find('size').text)
629 | self.dl_crc = data.find('crc').text
630 | if filename:
631 | return self.download(filename)
632 | return response
633 | else:
634 | raise ServerError("HTTP error {}".format(request.status_code))
635 |
636 | return response
637 |
638 | def download(self, filename):
639 | """ handle file download """
640 |
641 | request = self.session.get(
642 | self.baseurl + '/api/download/tmp.file?sessionid=' + self.sessionid,
643 | headers=self.headers,
644 | stream=True,
645 | **self.conn_options)
646 |
647 | if request.status_code == requests.codes.OK:
648 | size = 0
649 | crc = snscrc.CRC32_init
650 | try:
651 | with open(filename, "wb") as savefile:
652 | for chunk in request.iter_content(self.CHUNK_SIZE):
653 | savefile.write(chunk)
654 | size += len(chunk)
655 | crc = snscrc.update_crc32(chunk, crc)
656 | except Exception as exception:
657 | self.logger.log(logging.ERROR, str(exception))
658 | raise FileError("Can't save file")
659 |
660 | if size != self.dl_size:
661 | raise ServerError("Download error: {} bytes downloaded, expecting {} bytes".format(
662 | size, self.dl_size))
663 |
664 | crc = "%X" % (crc)
665 |
666 | if crc != self.dl_crc:
667 | raise ServerError("Download error: crc {}, expecting {}".format(crc, self.dl_crc))
668 |
669 | return Response(ret=100, code='00a00100', msg='OK',
670 | output='100 code=00a00100 msg="Ok"',
671 | xml='' +
672 | '')
673 |
674 | raise ServerError("HTTP error {}".format(request.status_code))
675 |
676 | def upload(self, filename):
677 | """ handle file upload """
678 |
679 | uploadh = open(filename, 'rb')
680 |
681 | data = MultipartEncoder(
682 | fields={'upload': uploadh}
683 | )
684 | headers = self.headers
685 | headers['Content-Type'] = data.content_type
686 |
687 | request = self.session.post(
688 | self.baseurl + '/api/upload?sessionid=' + self.sessionid,
689 | headers=headers,
690 | data=data,
691 | **self.conn_options)
692 |
693 | uploadh.close()
694 |
695 | if request.status_code == requests.codes.OK:
696 | nws_node = ElementTree.fromstring(request.content)
697 | code = int(nws_node.attrib['code'])
698 | self.nws_parse(code)
699 |
700 | return Response(code=nws_node[0].get('code'),
701 | ret=int(nws_node[0].get('ret')),
702 | msg=nws_node[0].get('msg'),
703 | output=format_output(request.content),
704 | xml=request.text)
705 |
706 | raise ServerError("HTTP error {}".format(request.status_code))
707 |
--------------------------------------------------------------------------------
/stormshield/sns/sslclient/__version__.py:
--------------------------------------------------------------------------------
1 | # major.minor.patch
2 | # major: breaking API change
3 | # minor: new functionality
4 | # patch: bugfix
5 | __version__ = "1.1.0"
6 |
--------------------------------------------------------------------------------
/tests/test_auth.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import os
4 | import unittest
5 | from stormshield.sns.sslclient import SSLClient
6 |
7 | APPLIANCE = os.getenv('APPLIANCE', "")
8 | SERIAL = os.getenv('SERIAL', "")
9 | PASSWORD = os.getenv('PASSWORD', "")
10 | SSLVERIFYPEER = os.getenv('SSLVERIFYPEER', "1") == "1";
11 |
12 | @unittest.skipIf(APPLIANCE=="", "APPLIANCE env var must be set to the ip/hostname of a running SNS appliance")
13 | @unittest.skipIf(SERIAL=="", "SERIAL env var must be set to the firewall serial number")
14 | @unittest.skipIf(PASSWORD=="", "PASSWORD env var must be set to the firewall password")
15 | class TestAuth(unittest.TestCase):
16 | """ Test authentication options """
17 |
18 | def test_sslverifyhost(self):
19 | """ Test sslverifyhost option """
20 |
21 | try:
22 | client = SSLClient(host=SERIAL, ip=APPLIANCE, user='admin', password=PASSWORD, sslverifyhost=True, sslverifypeer=SSLVERIFYPEER)
23 | self.assertTrue(1==1, "SSLClient connects with sslverifyhost=True")
24 | except:
25 | self.fail("SSLClient did not connect")
26 |
27 | response = client.send_command('LIST')
28 | self.assertEqual(response.ret, 100)
29 |
30 | client.disconnect()
31 |
--------------------------------------------------------------------------------
/tests/test_cert.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import os
4 | import unittest
5 | from stormshield.sns.sslclient import SSLClient
6 |
7 | APPLIANCE = os.getenv('APPLIANCE', "")
8 | FQDN = os.getenv('FQDN', "")
9 | PASSWORD = os.getenv('PASSWORD', "")
10 | CABUNDLE = os.getenv('CABUNDLE', "")
11 | CERT = os.getenv('CERT', "")
12 |
13 | @unittest.skipIf(APPLIANCE=="", "APPLIANCE env var must be set to the ip/hostname of a running SNS appliance")
14 | @unittest.skipIf(FQDN=="", "FQDN env var must be set to the firewall fqdn")
15 | @unittest.skipIf(PASSWORD=="", "PASSWORD env var must be set to the firewall password")
16 | @unittest.skipIf(CABUNDLE=="", "CABUNDLE env var must be set to the CA bundle file")
17 | @unittest.skipIf(CERT=="", "CERT env var must be set to the certificate file")
18 | class TestCert(unittest.TestCase):
19 | """ Test cabundle / certificate authentication options """
20 |
21 | def test_sslverifypeer(self):
22 | """ Test sslverifypeer option """
23 |
24 | # by default sslverifypeer is True
25 | try:
26 | client = SSLClient(host=APPLIANCE, user='admin', password=PASSWORD)
27 | self.fail("SSLClient should have failed (untrusted CA)")
28 | except Exception as exception:
29 | self.assertTrue(True, "SSLClient did not connect (untrusted CA)")
30 |
31 | try:
32 | client = SSLClient(host=APPLIANCE, user='admin', password=PASSWORD, sslverifypeer=False)
33 | self.assertTrue(True, "SSLClient connects with sslverifypeer=False")
34 | except Exception as exception:
35 | print(exception)
36 | self.fail("SSLClient did not connect")
37 |
38 | response = client.send_command('LIST')
39 | self.assertEqual(response.ret, 100)
40 |
41 | client.disconnect()
42 |
43 | def test_cabundle(self):
44 | """ Test cabundle option """
45 |
46 | try:
47 | client = SSLClient(host=FQDN, ip=APPLIANCE, user='admin', password=PASSWORD, sslverifyhost=True, cabundle=CABUNDLE)
48 | self.assertTrue(1==1, "SSLClient connects with cabundle")
49 | except Exception as exception:
50 | print(exception)
51 | self.fail("SSLClient did not connect")
52 |
53 | response = client.send_command('LIST')
54 | self.assertEqual(response.ret, 100)
55 |
56 | client.disconnect()
57 |
58 | def test_cert(self):
59 | """ Test user certificate authentication """
60 |
61 | try:
62 | client = SSLClient(host=FQDN, ip=APPLIANCE, usercert=CERT, sslverifyhost=True, cabundle=CABUNDLE)
63 | self.assertTrue(1==1, "SSLClient connects with cabundle")
64 | except Exception as exception:
65 | print(exception)
66 | self.fail("SSLClient did not connect")
67 |
68 | response = client.send_command('LIST')
69 | self.assertEqual(response.ret, 100)
70 |
71 | client.disconnect()
72 |
--------------------------------------------------------------------------------
/tests/test_configparser.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 | import unittest
5 | import json
6 |
7 | from stormshield.sns.configparser import ConfigParser
8 |
9 | class TestConfigParser(unittest.TestCase):
10 |
11 | def test_section(self):
12 | """ Get token from section """
13 |
14 | input = """101 code=00a01000 msg="Begin" format="section"
15 | [Result]
16 | Type="Firewall"
17 | Model="V50-A"
18 | MachineType="amd64"
19 | Version="3.7.1"
20 | ASQVersion="8.4.0"
21 | 100 code=00a00100 msg="Ok\""""
22 |
23 | expected = '3.7.1'
24 |
25 | config = ConfigParser(input)
26 | self.assertEqual(expected, config.get(section='Result', token='Version'))
27 |
28 | def test_default(self):
29 | """ Test default value """
30 |
31 | input = """101 code=00a01000 msg="Begin" format="section"
32 | [Result]
33 | Type="Firewall"
34 | Model="V50-A"
35 | MachineType="amd64"
36 | Version="3.7.1"
37 | ASQVersion="8.4.0"
38 | 100 code=00a00100 msg="Ok\""""
39 |
40 | expected = 1
41 |
42 | config = ConfigParser(input)
43 | self.assertEqual(expected, config.get(section='Result', token='DefaultConfig', default=1))
44 |
45 | def test_line(self):
46 | """ Get line from section """
47 |
48 | input = """101 code=00a01000 msg="Begin" format="list"
49 | [Filter]
50 | position=1; separator color="c0c0c0" comment="FQDN" collapse="0" nb_elements="1" first_ruleid="1"
51 | position=2; usage=0 match=0 ruleid=1: pass log from group="ruser"@Network_lan domain storm to rr.labo.int # Created on 2016-05-20 13:25:24,by admin (10.2.9.2)
52 | position=3; separator color="c0c0c0" comment="Office365" collapse="0" nb_elements="4" first_ruleid="2"
53 | position=4; usage=0 match=0 ruleid=2: pass log tos 8 from Network_lan to outlook.office365.com # Créée le 2016-06-23 15:17:04, par admin (10.2.9.2)
54 | position=5; usage=0 match=0 ruleid=3: pass settos 24 log from Network_lan to xsi.outlook.com # Créée le 2016-06-23 15:29:44, par admin (10.2.9.2)
55 | position=6; usage=0 match=0 ruleid=4: pass log from Network_lan to webdir.online.lync.com # Créée le 2016-06-23 15:29:47, par admin (10.2.9.2)
56 | position=7; separator color="c0c0c0" comment="DEFAULT" collapse="0" nb_elements="2" first_ruleid="14"
57 | position=8; usage=3 match=24994 ruleid=14: pass from any to any
58 | position=9; usage=0 match=0 ruleid=15: pass from any on out to Firewall_out port ssh # Allow SSH on OUT
59 | 100 code=00a00100 msg="Ok\"
60 | """
61 |
62 | expected = 'position=3; separator color="c0c0c0" comment="Office365" collapse="0" nb_elements="4" first_ruleid="2"'
63 |
64 | config = ConfigParser(input)
65 | self.assertEqual(expected, config.get(section='Filter', line=3))
66 |
67 | def test_get_sectionline(self):
68 | """ Get section_line section """
69 |
70 | input = """101 code=00a01000 msg="Begin" format="section_line"
71 | [Result]
72 | name=ntp1.stormshieldcs.eu keynum=none type=host
73 | name="ntp2.stormshieldcs.eu" keynum=none type=host
74 | 100 code=00a00100 msg="Ok\""""
75 |
76 | expected = [
77 | {"name":"ntp1.stormshieldcs.eu", "keynum":"none", "type":"host"},
78 | {"name":"ntp2.stormshieldcs.eu", "keynum":"none", "type":"host"}
79 | ]
80 |
81 | config = ConfigParser(input)
82 | self.assertEqual(expected, config.get(section='Result'))
83 |
84 |
85 | def test_getall(self):
86 | """ Get all tokens of a section """
87 |
88 | input="""101 code=00a01000 msg="Begin" format="section"
89 | [Server]
90 | 1=dnscache
91 | 2=dns1.google.com
92 | 100 code=00a00100 msg="Ok\""""
93 |
94 | expected = { "1":"dnscache", "2":"dns1.google.com"}
95 |
96 | config = ConfigParser(input)
97 | self.assertEqual(expected, config.get(section='Server'))
98 |
99 | def test_get_list(self):
100 | """ Get list section """
101 |
102 | input = """101 code=00a01000 msg="Begin" format="list"
103 | [Result]
104 | net1
105 | net2
106 | 100 code=00a00100 msg="Ok\""""
107 |
108 | expected = ['net1', 'net2']
109 |
110 | config = ConfigParser(input)
111 | self.assertEqual(expected, config.get(section='Result'))
112 |
113 | def test_case_insensitive(self):
114 | """ Test key names are case insensitive """
115 |
116 | input = """101 code=00a01000 msg="Begin" format="section"
117 | [Result]
118 | token1=value1
119 | token2=value2
120 | 100 code=00a00100 msg="Ok\""""
121 |
122 | config = ConfigParser(input)
123 | self.assertEqual('value1', config.get(section='result', token='TOKEN1'))
124 | self.assertEqual('value1', config.data['result']['TOKEN1'])
125 |
126 | def test_serialize(self):
127 | """ Test serialize data structure """
128 |
129 | input = """101 code=00a01000 msg="Begin" format="section"
130 | [Server]
131 | 1="dns1"
132 | 2="dns2"
133 | 100 code=00a00100 msg="Ok\""""
134 |
135 | expected = {"Server": { "1": "dns1", "2": "dns2"}}
136 |
137 | config = ConfigParser(input)
138 | self.assertEqual(json.dumps(expected), json.dumps(config.serialize_data()))
139 |
140 | input = """101 code=00a01000 msg="Begin" format="section_line"
141 | [Result]
142 | name=ntp1.stormshieldcs.eu keynum=none type=host
143 | name="ntp2.stormshieldcs.eu" keynum=none type=host
144 | 100 code=00a00100 msg="Ok\""""
145 |
146 | expected = {"Result": [
147 | {"name": "ntp1.stormshieldcs.eu", "keynum": "none", "type": "host"},
148 | {"name": "ntp2.stormshieldcs.eu", "keynum": "none", "type": "host"}
149 | ]}
150 |
151 | config = ConfigParser(input)
152 | self.assertEqual(json.dumps(expected), json.dumps(config.serialize_data()))
153 |
154 | def test_empty_value(self):
155 | """ Test empty value and value with ':' """
156 |
157 | input = """101 code=00a01000 msg="Begin" format="section_line"
158 | [Object]
159 | type=host global=0 name=Firewall_out ip=10.60.3.235 modify=0 comment=
160 | type=host global=0 name=dnscache ip=10.2.0.1 modify=1 comment= resolve=dynamic
161 | type=host global=0 name=myobject ip=1.2.3.4 modify=1 comment= mac=00:11:22:33:44:55
162 | 100 code=00a00100 msg="Ok\""""
163 |
164 | expected = {"Object": [
165 | {"type":"host", "global":"0", "name":"Firewall_out",
166 | "ip":"10.60.3.235", "modify":"0", "comment":""},
167 | {"type":"host", "global":"0", "name":"dnscache",
168 | "ip":"10.2.0.1", "modify":"1", "comment":"", "resolve":"dynamic"},
169 | {"type":"host", "global":"0", "name":"myobject",
170 | "ip":"1.2.3.4", "modify":"1", "comment":"", "mac":"00:11:22:33:44:55"}]}
171 |
172 | config = ConfigParser(input)
173 | self.assertEqual(expected, config.data)
174 |
175 | def test_slash_in_value(self):
176 | """ Test parsing of value with slash character """
177 |
178 | input = """101 code=00a01000 msg="Begin" format="section_line"
179 | [StaticRoutes]
180 | Remote=remote_net Address=172.21.0.0/24 Interface=out Gateway=remote_gw Protected=0 State=1 Comment=
181 | 100 code=00a00100 msg="Ok\""""
182 |
183 | expected = {'StaticRoutes': [
184 | {'Comment': '', 'Remote': 'remote_net', 'State': '1', 'Protected': '0',
185 | 'Address': '172.21.0.0/24', 'Interface': 'out', 'Gateway': 'remote_gw'}]}
186 |
187 | config = ConfigParser(input)
188 | self.assertEqual(expected, config.data)
189 |
190 | def test_arobase_in_value(self):
191 | """ Test parsing of value with @ character """
192 |
193 | input = """101 code=00a01000 msg="Begin" format="section_line"
194 | [Result]
195 | ruleid=1 state=on action=pass from=*@* to=*@* comment="default rule (pass all)"
196 | 100 code=00a00100 msg="Ok"\""""
197 |
198 | expected = {'Result': [
199 | {'ruleid': '1', 'state': 'on', 'action': 'pass', 'from': '*@*',
200 | 'to': '*@*', 'comment': 'default rule (pass all)'}]}
201 |
202 | config = ConfigParser(input)
203 | self.assertEqual(expected, config.data)
204 |
205 | def test_quote_in_token(self):
206 | """ Test parsing of token with ' character """
207 |
208 | input = """101 code=00a01000 msg="Begin" format="section_line"
209 | [Object]
210 | type=group global=0 name=it's_a_test nb_elements=2 modify=1 comment= used=0
211 | 100 code=00a00100 msg="Ok"\""""
212 |
213 | expected = {"Object": [
214 | {"type":"group", "global":"0", "name":"it's_a_test",
215 | "nb_elements":"2", "modify":"1", "comment":"", "used":"0"}]}
216 |
217 | config = ConfigParser(input)
218 | self.assertEqual(expected, config.data)
219 |
220 | if __name__ == '__main__':
221 | unittest.main()
222 |
--------------------------------------------------------------------------------
/tests/test_file.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 | from __future__ import unicode_literals
5 | import random
6 | import string
7 | import os
8 | import sys
9 | import tempfile
10 | import unittest
11 | import shutil
12 | from stormshield.sns.sslclient import SSLClient
13 |
14 | APPLIANCE = os.getenv('APPLIANCE', "")
15 | PASSWORD = os.getenv('PASSWORD', "")
16 | SSLVERIFYPEER = os.getenv('SSLVERIFYPEER', "1") == "1";
17 |
18 | @unittest.skipIf(APPLIANCE=="", "APPLIANCE env var must be set to the ip/hostname of a running SNS appliance")
19 | @unittest.skipIf(PASSWORD=="", "PASSWORD env var must be set to the firewall password")
20 | class TestFormatIni(unittest.TestCase):
21 | """ Test file upload & download """
22 |
23 | def setUp(self):
24 | self.client = SSLClient(host=APPLIANCE, user='admin', password=PASSWORD, sslverifyhost=False, sslverifypeer=SSLVERIFYPEER)
25 |
26 | self.tmpdir = tempfile.mkdtemp()
27 | self.upload = os.path.join(self.tmpdir, 'upload')
28 | self.download = os.path.join(self.tmpdir, 'download')
29 |
30 | def tearDown(self):
31 | self.client.disconnect()
32 | shutil.rmtree(self.tmpdir, ignore_errors=True)
33 |
34 | def test_upload_download(self):
35 | """ Test file upload and download """
36 |
37 | letters = string.ascii_letters + 'éèàÎîô'
38 |
39 | #generate a random file
40 | content = ( "[Filter] \n pass from network_internals to any #ASCII" +
41 | "".join( [random.choice(letters) for i in range(100)] )
42 | ).encode('utf-8')
43 | with open(self.upload, "wb") as fh:
44 | fh.write(content)
45 |
46 | response = self.client.send_command('CONFIG SLOT UPLOAD slot=1 name=testUpload < ' + self.upload)
47 | self.assertEqual(response.ret, 100)
48 |
49 | response = self.client.send_command('CONFIG SLOT DOWNLOAD slot=1 name=testUpload > ' + self.download)
50 | self.assertEqual(response.ret, 100)
51 |
52 | self.client.send_command('CONFIG SLOT DEFAULT type=filter slot=1')
53 | self.assertEqual(response.ret, 100)
54 |
55 | with open(self.download, "rb") as fh:
56 | downloaded = fh.read()
57 |
58 | self.assertEqual(content, downloaded)
59 |
60 | if __name__ == '__main__':
61 | unittest.main()
62 |
--------------------------------------------------------------------------------
/tests/test_format_ini.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import os
4 | import sys
5 | import unittest
6 | import re
7 |
8 | from stormshield.sns.sslclient import SSLClient
9 |
10 | APPLIANCE = os.getenv('APPLIANCE', "")
11 | PASSWORD = os.getenv('PASSWORD', "")
12 | SSLVERIFYPEER = os.getenv('SSLVERIFYPEER', "1") == "1";
13 |
14 | @unittest.skipIf(APPLIANCE=="", "APPLIANCE env var must be set to the ip/hostname of a running SNS appliance")
15 | @unittest.skipIf(PASSWORD=="", "PASSWORD env var must be set to the firewall password")
16 | class TestFormatIni(unittest.TestCase):
17 | """ Test INI format """
18 |
19 | def setUp(self):
20 | self.client = SSLClient(host=APPLIANCE, user='admin', password=PASSWORD, sslverifyhost=False, sslverifypeer=SSLVERIFYPEER)
21 |
22 | self.maxDiff = 5000
23 |
24 | def tearDown(self):
25 | self.client.disconnect()
26 |
27 | def test_raw(self):
28 | """ raw format """
29 |
30 | expected_re = """101 code=00a01000 msg="Begin" format="raw"
31 | AUTH.*
32 | CHPWD.*
33 | 100 code=00a00100 msg="Ok\""""
34 |
35 | response = self.client.send_command('HELP')
36 |
37 | self.assertTrue(re.match(expected_re, response.output, re.MULTILINE|re.DOTALL))
38 | self.assertEqual(response.ret, 100)
39 |
40 | def test_section(self):
41 | """ section format """
42 |
43 | expected = {
44 | "Global": {
45 | "State": "0",
46 | "RiskHalfLife": "21600",
47 | "RiskTTL": "86400"
48 | },
49 | "Alarm": {
50 | "Minor": "2",
51 | "Major": "10"
52 | },
53 | "Sandboxing" : {
54 | "Suspicious": "2",
55 | "Malicious": "50",
56 | "Failed": "0"
57 | },
58 | "Antivirus": {
59 | "Infected": "100",
60 | "Unknown": "2",
61 | "Failed": "0"
62 | }
63 | }
64 |
65 | response = self.client.send_command('CONFIG HOSTREP SHOW')
66 |
67 | self.assertEqual(response.data, expected)
68 | self.assertEqual(response.ret, 100)
69 |
70 | def test_section_line(self):
71 | """ section_line format """
72 |
73 | expected = {
74 | 'Object': [
75 | {'type': 'host', 'global': '0', 'name': '_TestHost1', 'ip': '10.10.5.5', 'modify': '1', 'comment': ''},
76 | {'type': 'host', 'global': '0', 'name': '_TestHost2', 'ip': '10.10.5.6', 'modify': '1', 'comment': ''},
77 | {'type': 'host', 'global': '0', 'name': '_TestHost3', 'ip': '10.10.5.7', 'modify': '1', 'comment': ''}
78 | ]
79 | }
80 |
81 | self.client.send_command('CONFIG OBJECT HOST NEW name=_TestHost1 ip=10.10.5.5')
82 | self.client.send_command('CONFIG OBJECT HOST NEW name=_TestHost2 ip=10.10.5.6')
83 | self.client.send_command('CONFIG OBJECT HOST NEW name=_TestHost3 ip=10.10.5.7')
84 |
85 | response = self.client.send_command('CONFIG OBJECT LIST type=host search=_Test* searchfield=name start=0')
86 |
87 | self.client.send_command('CONFIG OBJECT HOST DELETE name=_TestHost1')
88 | self.client.send_command('CONFIG OBJECT HOST DELETE name=_TestHost2')
89 | self.client.send_command('CONFIG OBJECT HOST DELETE name=_TestHost3')
90 |
91 | self.assertEqual(response.data, expected)
92 | self.assertEqual(response.ret, 100)
93 |
94 | def test_list(self):
95 | """ list format """
96 |
97 | expected = {'Result': ['network_internals', 'labo_networks']}
98 |
99 | response = self.client.send_command('CONFIG WEBADMIN ACCESS SHOW')
100 |
101 | self.assertEqual(response.data, expected)
102 | self.assertEqual(response.ret, 100)
103 |
104 | def test_xml(self):
105 | """ xml text output """
106 |
107 | expected = """
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 | """
116 |
117 | response = self.client.send_command('CONFIG FILTER EXPLICIT index=1 type=filter output=xml')
118 |
119 | self.assertEqual(response.xml, expected)
120 | self.assertEqual(response.ret, 100)
121 |
122 | if __name__ == '__main__':
123 | unittest.main()
124 |
--------------------------------------------------------------------------------
/tests/test_proxy.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import os
4 | import unittest
5 | from stormshield.sns.sslclient import SSLClient
6 |
7 | APPLIANCE = os.getenv('APPLIANCE', "")
8 | PASSWORD = os.getenv('PASSWORD', "")
9 | PROXY = os.getenv('PROXY', "")
10 |
11 | @unittest.skipIf(APPLIANCE=="", "APPLIANCE env var must be set to the ip/hostname of a running SNS appliance")
12 | @unittest.skipIf(PASSWORD=="", "PASSWORD env var must be set to the firewall password")
13 | @unittest.skipIf(PROXY=="", "PROXY env var must be set to proxy url")
14 | class TestProxy(unittest.TestCase):
15 | """ Test proxy option """
16 |
17 | def test_sslverifyhost(self):
18 | """ Test proxy option """
19 |
20 | try:
21 | client = SSLClient(host=APPLIANCE, user='admin', password=PASSWORD, sslverifypeer=False, proxy=PROXY)
22 | self.assertTrue(1==1, "SSLClient connects with proxy")
23 | except:
24 | self.fail("SSLClient did not connect")
25 |
26 | response = client.send_command('LIST')
27 | self.assertEqual(response.ret, 100)
28 |
29 | client.disconnect()
30 |
--------------------------------------------------------------------------------
/tests/test_utf8.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 | from __future__ import unicode_literals
5 | import os
6 | import sys
7 | import unittest
8 |
9 | from stormshield.sns.sslclient import SSLClient
10 |
11 | APPLIANCE = os.getenv('APPLIANCE', "")
12 | PASSWORD = os.getenv('PASSWORD', "")
13 | SSLVERIFYPEER = os.getenv('SSLVERIFYPEER', "1") == "1";
14 |
15 | @unittest.skipIf(APPLIANCE=="", "APPLIANCE env var must be set to the ip/hostname of a running SNS appliance")
16 | @unittest.skipIf(PASSWORD=="", "PASSWORD env var must be set to the firewall password")
17 | class TestUtf8(unittest.TestCase):
18 | """ Test INI format """
19 |
20 | def setUp(self):
21 | self.client = SSLClient(host=APPLIANCE, user='admin', password=PASSWORD, sslverifyhost=False, sslverifypeer=SSLVERIFYPEER)
22 | self.client.send_command('CONFIG OBJECT HOST NEW type=host name=hostutf8 ip=1.2.3.4 comment="comment with utf8 characters éè\u2713"')
23 |
24 | self.maxDiff = 5000
25 |
26 | def tearDown(self):
27 | self.client.send_command('CONFIG OBJECT HOST delete name=hostutf8')
28 | self.client.disconnect()
29 |
30 | def test_utf8(self):
31 | """ send and receive utf-8 content """
32 |
33 | expected = """101 code=00a01000 msg="Begin" format="section_line"
34 | [Object]
35 | type=host global=0 name=hostutf8 ip=1.2.3.4 modify=1 comment="comment with utf8 characters éè\u2713" type=host
36 | 100 code=00a00100 msg="Ok\""""
37 |
38 | response = self.client.send_command('CONFIG OBJECT LIST type=host search=hostutf8 start=0')
39 |
40 | self.assertEqual(response.output, expected)
41 | self.assertEqual(response.ret, 100)
42 |
43 |
44 | if __name__ == '__main__':
45 | unittest.main()
46 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | env_list = py3-urllib{1,2}
3 |
4 | [testenv]
5 | description = run unit tests
6 | deps =
7 | pytest
8 | urllib1: urllib3>=1.25.0,<2.0.0
9 | urllib2: urllib3>=2.0.0
10 | commands =
11 | pytest {posargs:tests}
12 | passenv = *
--------------------------------------------------------------------------------