summaryrefslogtreecommitdiffstats
path: root/web/TMP/tools
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--web/TMP/tools.html273
-rwxr-xr-xweb/TMP/tools.py269
-rw-r--r--web/TMP/tools/api/index.html11
-rwxr-xr-xweb/TMP/tools/api/v0/dns/a/index.py93
-rwxr-xr-xweb/TMP/tools/api/v0/ip/address/index.py70
-rwxr-xr-xweb/TMP/tools/api/v0/ipv4/address/index.py62
-rwxr-xr-xweb/TMP/tools/api/v0/ipv6/address/index.py62
7 files changed, 840 insertions, 0 deletions
diff --git a/web/TMP/tools.html b/web/TMP/tools.html
new file mode 100644
index 0000000..6b8d23a
--- /dev/null
+++ b/web/TMP/tools.html
@@ -0,0 +1,273 @@
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="author" content="system-administration@open-infrastructure.net">
+ <meta name="description" content="Open Infrastructure">
+ <meta name="generator" content="open-infrastructure.net">
+ <title>{hostname}</title>
+
+ <link rel="canonical" href="https://open-infrastructure.net">
+ <link rel="icon" href="/favicon.svg" type="image/svg+xml">
+
+ <!-- Bootstrap core CSS -->
+ <link href="/_static/bootstrap/css/bootstrap.min.css" rel="stylesheet">
+
+ <!-- Custom styles for this template -->
+ <link href="/_static/bootstrap-icons/bootstrap-icons.css" rel="stylesheet">
+ <link href="/_static/dejavu-fonts/dejavu-fonts.css" rel="stylesheet">
+
+ <link href="/_static/local/font.css" rel="stylesheet">
+ <link href="/_static/local/icon.css" rel="stylesheet">
+ </head>
+
+ <body>
+ <nav class="navbar navbar-expand-md navbar-dark fixed-top" style="background: #a40000">
+ <div class="container-fluid">
+ <a class="navbar-brand" href="/"><b>{hostname}</b></a>
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
+ <span class="navbar-toggler-icon"></span>
+ </button>
+ <div style="width: 4em"></div>
+ <div class="collapse navbar-collapse" id="navbarCollapse">
+ <ul class="navbar-nav me-auto mb-2 mb-md-0">
+ <li class="nav-item">
+ <a class="nav-link active" aria-current="page" href="/systems">Systems</a>
+ </li>
+ <li><div style="width: 1em"></div></li>
+ <li class="nav-item">
+ <a class="nav-link active" aria-current="page" href="/tools">Tools</a>
+ </li>
+ <li><div style="width: 1em"></div></li>
+ <li class="nav-item">
+ <a class="nav-link active" aria-current="page" href="/ttyd">ttyd</a>
+ </li>
+ <li><div style="width: 1em"></div></li>
+ <li class="nav-item">
+ <a class="nav-link active" aria-current="page" href="/netdata">netdata</a>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </nav>
+
+ <div class="container">
+ <main>
+ <!-- Begin content -->
+
+ <main role="main" class="container">
+
+ <div class="content">
+
+<a name="top"></a>
+<h1><i class="fa-fw far fa-tools"></i> Tools &nbsp;&nbsp;&nbsp; <small>(<a href="/tools/api">API</a>)</small></h1>
+<div style="height: 2em"></div>
+
+<script src="/_static/jquery/jquery.min.js"></script>
+
+<script>
+ $(document).ready(function(){
+ $("[type=button]").click(function() {
+ var command = $(this).data("command");
+ var protocol = $("input[name='protocol']:checked").val();
+ var target = document.getElementById("target").value;
+ var cgi = command + "&protocol=" + protocol + "&target=" + target;
+ $.ajax({url: cgi, success: function(result){
+ $("#output").text(result);
+ document.getElementById('output-hidden').style.display = 'block';
+ $(document).scrollTop( $("#output").offset().top -125);
+ }});
+ });
+
+ $("[type=reset]").click(function() {
+ $("#dual-stack").click();
+ $('.btn-group').find('reset').removeClass('active')
+ .end().find('[type="reset"]').prop('checked', false);
+ document.getElementById('output-hidden').style.display = 'none';
+ $("#target").focus();
+ $("#target").prop('autofocus');
+ });
+ });
+</script>
+
+<style type="text/css">
+ label, [type="button"], [type="reset"], [type="text"] {
+ margin-top: 0.5em;
+ }
+</style>
+
+<form id="form">
+ <div class="form-group">
+ <div class="row">
+ <div class="col-md-6">
+ <b>Target</b>
+ <input id="target" placeholder="IP address/subnet, FQDN, ASN, Internet resources..." style="width: 100%;" type="text" autofocus />
+
+ <div style="height: 1em"></div>
+ </div>
+
+ <div class="col-md-6">
+ <b>Settings</b><br />
+ <input class="btn btn-light btn-sm" type="reset" value="Reset" />
+
+ <div class="btn-group btn-group-toggle" data-toggle="buttons">
+ <label class="btn btn-light btn-sm active">
+ <input type="radio" name="protocol" id="dual-stack" value="dual-stack" checked> Dual-stack
+ </label>
+ <label class="btn btn-light btn-sm">
+ <input type="radio" name="protocol" id="ipv4-only" value="ipv4-only"> IPv4-only
+ </label>
+ <label class="btn btn-light btn-sm">
+ <input type="radio" name="protocol" id="ipv6-only" value="ipv6-only"> IPv6-only
+ </label>
+ </div>
+
+ <div style="height: 1em"></div>
+ </div>
+ </div>
+ </div>
+</form>
+
+<hr />
+
+<div class="row">
+ <div class="col-md-6">
+ <b>Network</b><br />
+ <button type="button" class="btn btn-success" data-command="/tools.py?command=ping">ping</button>
+ <button type="button" class="btn btn-success" data-command="/tools.py?command=traceroute">traceroute</button>
+ <button type="button" class="btn btn-success" data-command="/tools.py?command=tcptraceroute">tcptraceroute</button>
+ <button type="button" class="btn btn-success" data-command="/tools.py?command=whois">whois</button>
+
+ <div style="height: 1em"></div>
+
+ <b>Security</b><br />
+ <button type="button" class="btn btn-warning" data-command="/tools.py?command=nmap">nmap</button>
+ <button type="button" class="btn btn-warning" data-command="/tools.py?command=ssh-audit">ssh-audit</button>
+ <button type="button" class="btn btn-warning" data-command="/tools.py?command=testssl">testssl</button>
+
+ <div style="height: 1em"></div>
+
+ <b>other</b><br />
+ <button type="button" class="btn btn-info" data-command="/tools.py?command=my-ip&target=none">My IP</button>
+ <button type="button" class="btn btn-info" data-command="/tools.py?command=my-browser&target=none">My browser</button>
+
+ <div style="height: 1em"></div>
+ </div>
+
+ <div class="col-md-6">
+ <b>DNS</b><br />
+ <small><b>Address-related records</b></small><br />
+ <button type="button" class="btn btn-primary" data-command="/tools.py?command=kdig&query=ANY">ANY</button>
+ <button type="button" class="btn btn-primary" data-command="/tools.py?command=kdig&query=A">A</button>
+ <button type="button" class="btn btn-primary" data-command="/tools.py?command=kdig&query=AAAA">AAAA</button>
+ <button type="button" class="btn btn-primary" data-command="/tools.py?command=kdig&query=CNAME">CNAME</button>
+ <button type="button" class="btn btn-primary" data-command="/tools.py?command=kdig&query=DNAME">DNAME</button>
+ <button type="button" class="btn btn-primary" data-command="/tools.py?command=kdig&query=PTR">PTR</button>
+
+ <div style="height: 1em"></div>
+
+ <small><b>Informational records</b></small><br />
+ <button type="button" class="btn btn-info" data-command="/tools.py?command=kdig&query=APL">APL</button>
+ <button type="button" class="btn btn-info" data-command="/tools.py?command=kdig&query=HINFO">HINFO</button>
+ <button type="button" class="btn btn-info" data-command="/tools.py?command=kdig&query=LOC">LOC</button>
+ <button type="button" class="btn btn-info" data-command="/tools.py?command=kdig&query=RP">RP</button>
+ <button type="button" class="btn btn-info" data-command="/tools.py?command=kdig&query=SOA">SOA</button>
+ <button type="button" class="btn btn-info" data-command="/tools.py?command=kdig&query=SRV">SRV</button>
+ <button type="button" class="btn btn-info" data-command="/tools.py?command=kdig&query=TXT">TXT</button>
+
+ <div style="height: 1em"></div>
+
+ <small><b>DNSSEC records</b></small><br />
+ <button type="button" class="btn btn-secondary" data-command="/tools.py?command=kdig&query=CDNSKEY">CDNSKEY</button>
+ <button type="button" class="btn btn-secondary" data-command="/tools.py?command=kdig&query=CDS">CDS</button>
+ <button type="button" class="btn btn-secondary" data-command="/tools.py?command=kdig&query=DNSKEY">DNSKEY</button>
+ <button type="button" class="btn btn-secondary" data-command="/tools.py?command=kdig&query=DS">DS</button>
+ <button type="button" class="btn btn-secondary" data-command="/tools.py?command=kdig&query=RRSIG">RRSIG</button>
+
+ <div style="height: 1em"></div>
+
+ <small><b>Security-related records</b></small><br />
+ <button type="button" class="btn btn-warning" data-command="/tools.py?command=kdig&query=CAA">CAA</button>
+ <button type="button" class="btn btn-warning" data-command="/tools.py?command=kdig&query=NSEC3">NSEC3</button>
+ <button type="button" class="btn btn-warning" data-command="/tools.py?command=kdig&query=NSEC3PARAM">NSEC3PARAM</button>
+ <button type="button" class="btn btn-warning" data-command="/tools.py?command=kdig&query=SSHFP">SSHFP</button>
+ <button type="button" class="btn btn-warning" data-command="/tools.py?command=kdig&query=TLSA">TLSA</button>
+
+ <div style="height: 1em"></div>
+
+ <small><b>other records and types</b></small><br />
+ <button type="button" class="btn btn-success" data-command="/tools.py?command=kdig&query=AXFR">AXFR*</button>
+ <button type="button" class="btn btn-success" data-command="/tools.py?command=kdig&query=MX">MX</button>
+ <button type="button" class="btn btn-success" data-command="/tools.py?command=kdig&query=NS">NS</button>
+
+ <div style="height: 1em"></div>
+
+ <small><b>Legacy records</b></small><br />
+ <button type="button" class="btn btn-danger" data-command="/tools.py?command=kdig&query=NSEC">NSEC</button>
+ <button type="button" class="btn btn-danger" data-command="/tools.py?command=kdig&query=SPF">SPF</button>
+
+ <div style="height: 1em"></div>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col-md-6">
+ <small><b>Notes:</b>
+ <ul>
+ <li>testssl can take up to 5min (with currently no output until the end)</li>
+ </ul></small>
+
+ <div style="height: 1em"></div>
+ </div>
+
+ <div class="col-md-6">
+ <small><b>*</b> only available for BFH authoritative zones</small>
+
+ <div style="height: 1em"></div>
+ </div>
+</div>
+
+<hr />
+
+<div id="output-hidden" style="display: none;">
+<a name="output"></a>
+<a href="#top"><button type="button" class="btn btn-light btn-sm float-right">&uarr;</button></a><br />
+<b>Output</b><br />
+<pre>
+<textarea id="output" readonly rows="25" style="background: #f1f1f1; width: 100%;"></textarea>
+</pre>
+</div>
+
+<div style="height: 1em"></div>
+
+
+ </div>
+
+ </main><!-- /.container -->
+
+
+
+
+ <!-- End content -->
+ </main>
+
+ <div style="height: 4em"></div>
+
+ <footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top">
+ <p class="col-md-4 mb-0 text-muted">&copy; 2022</p>
+
+ <ul class="nav col-md-4 justify-content-end">
+ <li class="nav-item"><a href="https://open-infrastructure.net/contact" class="nav-link px-2 text-muted">Contact</a></li>
+ <li class="nav-item"><a href="https://open-infrastructure.net/legal" class="nav-link px-2 text-muted">Legal</a></li>
+ </ul>
+ </footer>
+ </div>
+
+ <!-- Bootstrap core JS -->
+ <script src="/_static/popperjs/popper.min.js"></script>
+ <script src="/_static/bootstrap/js/bootstrap.min.js"></script>
+
+ <!-- Custom scripts for this template -->
+ </body>
+</html>
diff --git a/web/TMP/tools.py b/web/TMP/tools.py
new file mode 100755
index 0000000..c8dab03
--- /dev/null
+++ b/web/TMP/tools.py
@@ -0,0 +1,269 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2013-2021 Daniel Baumann <daniel@debian.org>
+#
+# SPDX-License-Identifier: GPL-3.0+
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Dependencies:
+# sudo apt install iputils-ping traceroute whois nmap ssh-audit testssl.sh geoip-bin geoip-database knot-dnsutils
+# sudo apt install python3-pygments
+
+from cgi import FieldStorage
+from datetime import datetime
+import ipaddress
+from os import getenv
+from subprocess import Popen, PIPE
+from sys import exit
+
+def filter_nameservers(servers, protocol):
+ nameservers= []
+
+ for server in servers:
+ name = server.rstrip().rstrip('.')
+
+ if protocol == 'ipv6-only':
+ command = 'kdig -6'
+ options = ' -t AAAA +short -q '
+ elif protocol == 'ipv4-only':
+ command = 'kdig -4'
+ options = ' -t A +short -q '
+ else:
+ command = 'kdig'
+ options = ' +short -q '
+
+ command_line = (command + options + name).split()
+ kdig = Popen(command_line, stdout=PIPE)
+ address = kdig.stdout.readline()
+
+ if address:
+ nameservers.append(name)
+
+ return nameservers
+
+def get_nameserver(name, protocol):
+ nameservers = []
+
+ if protocol == 'ipv6-only':
+ command = 'kdig -6'
+ elif protocol == 'ipv4-only':
+ command = 'kdig -4'
+ else:
+ command = 'kdig'
+
+ options = ' -t NS +short -q '
+
+ command_line = (command + options + name).split()
+ kdig = Popen(command_line, stdout=PIPE)
+ servers = kdig.stdout.readlines()
+
+ count = 0
+ while not servers and count < 10:
+ name = name.split('.')
+ del name[0]
+ name = '.'.join(name)
+
+ command_line = (command + options + name).split()
+ kdig = Popen(command_line, stdout=PIPE)
+ servers = kdig.stdout.readlines()
+
+ count += 1
+
+ names = []
+ for server in servers:
+ name = server.rstrip().decode('utf-8').rstrip('.')
+ names.append(name)
+
+ nameservers = filter_nameservers(names, protocol)
+ return nameservers
+
+def run_command(command):
+ process = Popen(command, stdout=PIPE)
+ empty_lines = 0
+ while True:
+ line = process.stdout.readline().rstrip()
+ if not line:
+ empty_lines = empty_lines + 1
+ if empty_lines > 2:
+ break
+ else:
+ print()
+ else:
+ empty_lines = 0
+ yield line.decode('utf-8')
+
+def main():
+ form = FieldStorage()
+
+ if form.getvalue("command"):
+ Command = form.getvalue("command").split()[0]
+
+ if "target" in form:
+ Target = form.getvalue("target").split()[0]
+
+ if "protocol" in form:
+ Protocol = form.getvalue("protocol").split()[0]
+
+ if "query" in form:
+ Query = form.getvalue("query").split()[0]
+
+ if Command and Protocol and Target:
+ print('Content-Type: text/html\n')
+
+ Date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+
+ if Command == 'kdig':
+ if Protocol == 'ipv6-only':
+ options = ' -6'
+ elif Protocol == 'ipv4-only':
+ options = ' -4'
+ else:
+ options = ''
+
+ if Query == 'PTR':
+ arpa = ipaddress.ip_address(Target).reverse_pointer
+
+ nameserver = get_nameserver(arpa, Protocol)
+
+ protocol_passed = False
+
+ for server in nameserver:
+ check_options = options + ' @' + server + ' -t ' + Query + ' -q '
+
+ command_line = (Command + ' +short' + check_options + arpa).split()
+ kdig = Popen(command_line, stdout=PIPE)
+ protocol_check = kdig.stdout.readline()
+
+ if protocol_check:
+ protocol_passed = True
+ break
+
+ if not protocol_passed:
+ print('IPv6-only query but no IPv6 enabled nameserver available for ' + Target + '\n\n')
+ print('--')
+ print('Run: ' + str(command_line))
+ print('Date: ' + Date)
+
+ exit(0)
+
+ options = options + ' @' + server + ' -x '
+ else:
+ nameserver = get_nameserver(Target, Protocol)
+
+ protocol_passed = False
+
+ for server in nameserver:
+ check_options = options + ' @' + server + ' -t ' + Query + ' -q '
+
+ command_line = (Command + ' +short' + check_options + Target).split()
+ kdig = Popen(command_line, stdout=PIPE)
+ protocol_check = kdig.stdout.readline()
+
+ if protocol_check:
+ protocol_passed = True
+ break
+
+ if not protocol_passed:
+ print('IPv6-only query but no IPv6 enabled nameserver available for ' + Target + '\n\n')
+ print('--')
+ print('Run: ' + str(command_line))
+ print('Date: ' + Date)
+
+ exit(0)
+
+ options = options + ' @' + server + ' -t ' + Query + ' -q '
+ elif Command == 'ping':
+ if Protocol == 'ipv6-only':
+ options = ' -6'
+ elif Protocol == 'ipv4-only':
+ options = ' -4'
+ else:
+ options = ''
+ options = options + ' -c3 '
+ elif Command == 'traceroute':
+ if Protocol == 'ipv6-only':
+ options = ' -6'
+ elif Protocol == 'ipv4-only':
+ options = ' -4'
+ else:
+ options = ''
+ options = options + ' '
+ elif Command == 'tcptraceroute':
+ Command = 'traceroute'
+ if Protocol == 'ipv6-only':
+ options = ' -6'
+ elif Protocol == 'ipv4-only':
+ options = ' -4'
+ else:
+ options = ''
+ options = options + ' -T '
+ elif Command == 'nmap':
+ if Protocol == 'ipv6-only':
+ options = ' -6'
+ else:
+ options = ' '
+ #-O -T5
+ elif Command == 'ssh-audit':
+ if Protocol == 'ipv6-only':
+ options = ' -6'
+ elif Protocol == 'ipv4-only':
+ options = ' -4'
+ else:
+ options = ''
+ options = options + ' --no-colors '
+ elif Command == 'testssl':
+ options = ' --color 0 '
+ elif Command == 'whois':
+ options = ' -H '
+ else:
+ options = ' '
+
+ if Command == 'my-ip':
+ command_line = ''
+
+ ip_address = getenv('REMOTE_ADDR')
+ print('IP address: ' + ip_address)
+
+ # TODO: show reverse DNS
+
+ if ':' in ip_address:
+ print('IP version: IPv6')
+ process = Popen(['geoiplookup6', ip_address], stdout=PIPE)
+ else:
+ print('IP version: IPv4')
+ process = Popen(['geoiplookup', ip_address], stdout=PIPE)
+
+ geoiplookup = process.stdout.readline().rstrip()
+ country = geoiplookup.decode('utf-8').split(':')[1]
+ print('Country:' + country + '\n\n')
+ elif Command == 'my-browser':
+ command_line = ''
+ print('User-Agent: ' + getenv('HTTP_USER_AGENT', 'n/a') + '\n\n')
+ else:
+ command_line = Command + options + Target
+
+ for path in run_command(command_line.split()):
+ print(path)
+
+ print('--')
+ print('Date: ' + Date)
+
+ if command_line:
+ print('Run: ' + command_line)
+
+ exit(0)
+
+if __name__ == '__main__':
+ main()
diff --git a/web/TMP/tools/api/index.html b/web/TMP/tools/api/index.html
new file mode 100644
index 0000000..a5f22f2
--- /dev/null
+++ b/web/TMP/tools/api/index.html
@@ -0,0 +1,11 @@
+<html>
+ <h1>tools.bfh.info</h1>
+
+ <h2>API</h2>
+
+ <ul>
+ <li><a href="/tools/api/v0/ip/address">/tools/api/v0/ip/address</a></li>
+ <li><a href="/tools/api/v0/ipv4/address">/tools/api/v0/ipv4/address</a></li>
+ <li><a href="/tools/api/v0/ipv6/address">/tools/api/v0/ipv6/address</a></li>
+ </ul>
+</html>
diff --git a/web/TMP/tools/api/v0/dns/a/index.py b/web/TMP/tools/api/v0/dns/a/index.py
new file mode 100755
index 0000000..88b1b03
--- /dev/null
+++ b/web/TMP/tools/api/v0/dns/a/index.py
@@ -0,0 +1,93 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2013-2021 Daniel Baumann <daniel@debian.org>
+#
+# SPDX-License-Identifier: GPL-3.0+
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+from ipaddress import ip_address
+from json import dumps
+from os import getenv
+from subprocess import Popen, PIPE
+from sys import exit
+
+from pygments import highlight
+from pygments.lexers import JsonLexer
+from pygments.formatters import TerminalFormatter
+
+def run_command(command):
+ process = Popen(command, stdout=PIPE)
+ empty_lines = 0
+ while True:
+ line = process.stdout.readline().rstrip()
+ if not line:
+ empty_lines = empty_lines + 1
+ if empty_lines > 2:
+ break
+ else:
+ print()
+ else:
+ empty_lines = 0
+ yield line.decode('utf-8')
+
+def v0_dns_a():
+ a = 'google.com'
+ cgi = getenv('GATEWAY_INTERFACE')
+
+ #command_line = 'kdig +json A ' + a + ' | jq -r -M \'.answer | .[] | .rdata\''
+ command_line = 'kdig +json A ' + a
+
+ kdig = Popen(command_line.split(), stdout=PIPE)
+
+# try:
+# ip = str(ip_address(address))
+# if ip_address(address).version == 4:
+# ip_version = 'ipv4'
+# elif ip_address(address).version == 6:
+# ip_version = 'ipv6'
+# else:
+# ip_version = None
+# message = 'valid IP address'
+# status = True
+# except ValueError:
+# ip = None
+# ip_version = None
+# message = 'invalid IP address'
+# status = False
+
+ status = True
+ message = 'valid DNS record'
+
+ json = \
+ {
+ 'data': {
+ 'record': a,
+ },
+ 'meta': {
+ 'status': status,
+ 'message': message,
+ },
+ }
+
+ if cgi:
+ print('Content-Type: application/json\n')
+ print(dumps(json))
+ else:
+ print(highlight(dumps(json, indent=4), JsonLexer(), TerminalFormatter()))
+
+ exit(0)
+
+if __name__ == '__main__':
+ v0_dns_a()
diff --git a/web/TMP/tools/api/v0/ip/address/index.py b/web/TMP/tools/api/v0/ip/address/index.py
new file mode 100755
index 0000000..49e4971
--- /dev/null
+++ b/web/TMP/tools/api/v0/ip/address/index.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2013-2021 Daniel Baumann <daniel@debian.org>
+#
+# SPDX-License-Identifier: GPL-3.0+
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+from ipaddress import ip_address
+from json import dumps
+from os import getenv
+from sys import exit
+
+from pygments import highlight
+from pygments.lexers import JsonLexer
+from pygments.formatters import TerminalFormatter
+
+def v0_ip_address():
+ address = getenv('REMOTE_ADDR')
+ cgi = getenv('GATEWAY_INTERFACE')
+
+ try:
+ ip = str(ip_address(address))
+ if ip_address(address).version == 4:
+ ip_version = 'ipv4'
+ elif ip_address(address).version == 6:
+ ip_version = 'ipv6'
+ else:
+ ip_version = None
+ message = 'valid IP address'
+ status = True
+ except ValueError:
+ ip = None
+ ip_version = None
+ message = 'invalid IP address'
+ status = False
+
+ json = \
+ {
+ 'data': {
+ 'ip_address': ip,
+ 'ip_version': ip_version,
+ },
+ 'meta': {
+ 'status': status,
+ 'message': message,
+ },
+ }
+
+ if cgi:
+ print('Content-Type: application/json\n')
+ print(dumps(json))
+ else:
+ print(highlight(dumps(json, indent=4), JsonLexer(), TerminalFormatter()))
+
+ exit(0)
+
+if __name__ == '__main__':
+ v0_ip_address()
diff --git a/web/TMP/tools/api/v0/ipv4/address/index.py b/web/TMP/tools/api/v0/ipv4/address/index.py
new file mode 100755
index 0000000..7a08c34
--- /dev/null
+++ b/web/TMP/tools/api/v0/ipv4/address/index.py
@@ -0,0 +1,62 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2013-2021 Daniel Baumann <daniel@debian.org>
+#
+# SPDX-License-Identifier: GPL-3.0+
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+from ipaddress import IPv4Address
+from json import dumps
+from os import getenv
+from sys import exit
+
+from pygments import highlight
+from pygments.lexers import JsonLexer
+from pygments.formatters import TerminalFormatter
+
+def v0_ipv4_address():
+ address = getenv('REMOTE_ADDR')
+ cgi = getenv('GATEWAY_INTERFACE')
+
+ try:
+ ip = str(IPv4Address(address))
+ message = 'valid IPv4 address'
+ status = True
+ except ValueError:
+ ip = None
+ message = 'invalid IPv4 address'
+ status = False
+
+ json = \
+ {
+ 'data': {
+ 'ipv4_address': ip,
+ },
+ 'meta': {
+ 'status': status,
+ 'message': message,
+ },
+ }
+
+ if cgi:
+ print('Content-Type: application/json\n')
+ print(dumps(json))
+ else:
+ print(highlight(dumps(json, indent=4), JsonLexer(), TerminalFormatter()))
+
+ exit(0)
+
+if __name__ == '__main__':
+ v0_ipv4_address()
diff --git a/web/TMP/tools/api/v0/ipv6/address/index.py b/web/TMP/tools/api/v0/ipv6/address/index.py
new file mode 100755
index 0000000..0746a83
--- /dev/null
+++ b/web/TMP/tools/api/v0/ipv6/address/index.py
@@ -0,0 +1,62 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2013-2021 Daniel Baumann <daniel@debian.org>
+#
+# SPDX-License-Identifier: GPL-3.0+
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+from ipaddress import IPv6Address
+from json import dumps
+from os import getenv
+from sys import exit
+
+from pygments import highlight
+from pygments.lexers import JsonLexer
+from pygments.formatters import TerminalFormatter
+
+def v0_ipv6_address():
+ address = getenv('REMOTE_ADDR')
+ cgi = getenv('GATEWAY_INTERFACE')
+
+ try:
+ ip = str(IPv6Address(address))
+ message = 'valid IPv6 address'
+ status = True
+ except ValueError:
+ ip = None
+ message = 'invalid IPv6 address'
+ status = False
+
+ json = \
+ {
+ 'data': {
+ 'ipv6_address': ip,
+ },
+ 'meta': {
+ 'status': status,
+ 'message': message,
+ },
+ }
+
+ if cgi:
+ print('Content-Type: application/json\n')
+ print(dumps(json))
+ else:
+ print(highlight(dumps(json, indent=4), JsonLexer(), TerminalFormatter()))
+
+ exit(0)
+
+if __name__ == '__main__':
+ v0_ipv6_address()