commit 02e2c3592a0ca7a4676bdb941c07d002de1033ad Author: Nikola Mitev Date: Fri Nov 8 16:27:00 2024 +0000 initial version diff --git a/Integrations/DNSTest/README.md b/Integrations/DNSTest/README.md new file mode 100644 index 0000000..501f0c8 --- /dev/null +++ b/Integrations/DNSTest/README.md @@ -0,0 +1,25 @@ +A simple tool for testing DNS, useful if you do not have access to the underlying server. + +## Configure DNSTest on Cortes XSOAR +1. Navigate to **Settings** > **Integrations** > **Servers & Services**. +2. Search for DNSTest. +3. Click **Add instance** to create and configure a new integration instance. + +| **Parameter** | **Description** | **Required** | +| --- | --- | --- | +| Default domain | The domain to query for during inital testing (default: google.com)| False | +| Timeout | Time in seconds to wait for response from DNS server (default: 1 sec) | False | + +4. Click **Test** to verify operation, using default or provided parameters. + +## Commands +Run these commands from the Cortex XSOAR CLI +### dns-test-get-resolvers +Returns the nameserver IP addresses configured for the host (e.g. in /etc/resolv.conf) + +Example: !dns-test-get-resolvers + +### dns-test-resolve-domain +Queries all available resolvers for A, AAAA and CNAME records for the provided domain name and returns the results. Optionally increase the wait time for the query by passing a timeout value greater than 1 + +Example: !dns-test-resolve-domain domain=test.com [timeout=5] diff --git a/Integrations/DNSTest/dnstest.py b/Integrations/DNSTest/dnstest.py new file mode 100644 index 0000000..4ca4801 --- /dev/null +++ b/Integrations/DNSTest/dnstest.py @@ -0,0 +1,148 @@ +register_module_line('DNSTest', 'start', __line__()) +demisto.debug('pack name = DNSTest, pack version = 1.0.0') + +import dns.resolver +from time import sleep + +def get_dns_resolvers(): + # This function retrieves the DNS resolvers from the server configuration. + resolver = dns.resolver.get_default_resolver() + return resolver.nameservers + +def resolve_domain(domain, timeout=1, iterations=100, delay=0): + # This function resolves a given domain using all locally configured resolvers. + resolvers = get_dns_resolvers() + rtypes = ['A', 'AAAA', 'CNAME'] + + result = {} + for resolver in resolvers: + for rtype in rtypes: + demisto.debug(f'Resolving {domain} using {resolver} for {rtype} records...') + # run every query 100 times to handle cases where the DNS server is not responding. + errors = set() + for i in range(iterations): + answers = [] + try: + a = dns.resolver.resolve_at(resolver, domain, rtype, lifetime=timeout) + + if a: + answers = [str(answer) for answer in a] + answers.sort() + + except dns.resolver.NXDOMAIN: + error = f'Domain {domain} does not exist.' + errors.add(error) + demisto.info(error) + except dns.resolver.NoAnswer: + error = f'No {rtype} records found for domain {domain}.' + errors.add(error) + demisto.info(error) + except dns.resolver.Timeout: + error = f'Timeout occurred while resolving domain {domain}.' + errors.add(error) + demisto.info(error) + except Exception as e: + error = f'An error occurred while resolving domain {domain}: {str(e)}' + errors.add(error) + demisto.info(error) + + demisto.info(f'Results for {resolver} and {rtype}: {answers}') + + if resolver in result and rtype in result[resolver]: + demisto.debug(f'Previous results for {resolver} and {rtype} already exist.') + if answers: + if not result[resolver][rtype]['answers'] or answers == result[resolver][rtype]['answers']: + demisto.debug(f'incrementing successes') + result[resolver][rtype]['successes'] += 1 + else: + demisto.info(f'got different answer for {rtype} from {resolver}: {answerlist}') + result[resolver][rtype].setdefault('variants', []).append(answerlist) + demisto.debug(f'incrementing successes') + result[resolver][rtype]['successes'] += 1 + else: + demisto.debug(f'incrementing failures') + result[resolver][rtype]['failures'] += 1 + elif resolver in result: + demisto.debug(f'Adding initial record for {rtype} from {resolver}.') + if answers: + result[resolver][rtype] = {'answers': [str(answer) for answer in answers], 'successes': 1} + else: + result[resolver][rtype] = {'answers': [], 'failures': 1, 'successes': 0} + else: + demisto.debug(f'Adding initial result for {resolver}.') + if answers: + result[resolver] = {rtype: {'answers': [str(answer) for answer in answers],'successes': 1}} + else: + result[resolver] = {rtype: {'answers': [], 'failures': 1, 'successes': 0}} + + sleep(delay) + + if errors: + demisto.debug(f'errors for {resolver} and {rtype}: {errors}') + result[resolver][rtype]['errors'] = list(errors) + + return result + +def test_module(default_domain, timeout): + """ + This is the test function that runs when the module is loaded for the first time. + It tests the module's functions by calling them with sample inputs. + """ + + # Test resolve_domain function + domain = 'google.com' + result = resolve_domain(default_domain, timeout, iterations=1) + + # Test get_dns_resolvers function + resolvers = get_dns_resolvers() + + if isinstance(resolvers, list) and len(resolvers) > 0: + getresolversok = True + else: + return 'Get resolvers test failed' + + if isinstance(result, dict) and len(result) > 0: + resolveok = True + else: + return 'Resolve test failed' + + if resolveok and getresolversok: + return 'ok' + + +def main(): + """ + Parse and Validate the commands, parameters, arguments + and processes the api requests. + """ + + command = demisto.command() + demisto.info(f'Executing command {command}') + + args = demisto.args() + params = demisto.params() + timeout = int(params.get('timeout', 1)) + default_domain = params.get('default_domain', 'google.com') + delay = int(params.get('delay', 0)) + iterations = int(params.get('iterations', 100)) + + if command == 'dns-test-resolve-domain': + domain = args.get('domain') + result = resolve_domain(domain, timeout, iterations=iterations, delay=delay) + return_results(result) + + elif command == 'dns-test-get-resolvers': + resolvers = get_dns_resolvers() + return_results(resolvers) + + elif command == 'test-module': + result = test_module(default_domain, timeout) + return_results(result) + + else: + return_error(f'Unsupported command: {command}') + +if __name__ in ['__main__', '__builtin__', 'builtins']: + main() + +register_module_line('DNSTest', 'end', __line__()) diff --git a/Integrations/DNSTest/dnstest.yml b/Integrations/DNSTest/dnstest.yml new file mode 100644 index 0000000..05538a7 --- /dev/null +++ b/Integrations/DNSTest/dnstest.yml @@ -0,0 +1,39 @@ +commonfields: + id: DNSTest + version: -1 +name: DNSTest +display: DNSTest +category: Utilities +configuration: +- display: DNS query timeout + name: timeout + defaultvalue: "1" + type: 0 + required: false + additionalinfo: How long to wait for reply from the DNS server (default 1s) +- display: Default domain + name: default_domain + defaultvalue: "google.com" + type: 0 + required: false + additionalinfo: The default domain used to test operation. May need to be configured if the local resolver is not recursive. +script: + script: "" + type: python + commands: + - name: dns-test-resolve-domain + description: Resolve a given domain using all locally configured resolvers + arguments: + - name: domain + description: The domain to resolve + required: true + - name: dns-test-get-resolvers + arguments: [] + description: Get the locally configured DNS resolvers + dependencies: + - name: dnspython + version: ">=2.7.0" + dockerimage: demisto/py3-tools:1.0.0.87415 + isfetch: false + runonce: true + subtype: python3 diff --git a/ReleaseNotes/0_9.md b/ReleaseNotes/0_9.md new file mode 100644 index 0000000..c788bb2 --- /dev/null +++ b/ReleaseNotes/0_9.md @@ -0,0 +1,3 @@ +Integrations +DNSTest + - initial release diff --git a/pack_metadata.json b/pack_metadata.json new file mode 100644 index 0000000..21cd393 --- /dev/null +++ b/pack_metadata.json @@ -0,0 +1,31 @@ +{ + "name": "DNSTest", + "description": "A tool for troubleshooting and testing local DNS", + "support": "developer", + "currentVersion": "0.9", + "author": "Nik Mitev", + "email": "xsoar@mitev.net", + "devEmail": "xsoar@mitev.net", + "categories": [ + "Utilities" + ], + "tags": [ + "dns", + "troubleshooting" + ], + "created": "2024-11-05T00:00:00Z", + "useCases": [ + "Troubleshooting DNS issues", + "Testing local DNS configurations" + ], + "keywords": [ + "dns", + "debugging" + ], + "dependencies": { + "dnspython": ">=2.7.0" + }, + "githubUser": [ + "nikmit" + ] +}