diff --git a/apps/api/api/app.py b/apps/api/api/app.py index 62a04f3..7246f25 100644 --- a/apps/api/api/app.py +++ b/apps/api/api/app.py @@ -3,7 +3,7 @@ from gevent.pywsgi import WSGIServer from helpers import access_token_required import config -from checkers import HttpChecker, ICMPChecker +from checkers import HttpChecker, ICMPChecker, TCPPortChecker app = Flask(__name__) @@ -22,6 +22,20 @@ def http_check(): return jsonify(checker.check()) +@app.route('/tcp_port') +@access_token_required +def tcp_port_check(): + target = request.args.get("target", None) + port = int(request.args.get("port", 80)) + + if not target: + abort(400) + + checker = TCPPortChecker(target, port) + + return jsonify(checker.check()) + + @app.route('/icmp') @access_token_required def icmp_check(): diff --git a/apps/api/api/checkers/__init__.py b/apps/api/api/checkers/__init__.py index b03b13b..bf6f8b1 100644 --- a/apps/api/api/checkers/__init__.py +++ b/apps/api/api/checkers/__init__.py @@ -1,2 +1,3 @@ from .http import HttpChecker from .icmp import ICMPChecker +from .tcp_port import TCPPortChecker diff --git a/apps/api/api/checkers/tcp_port.py b/apps/api/api/checkers/tcp_port.py index 4efc487..369ef63 100644 --- a/apps/api/api/checkers/tcp_port.py +++ b/apps/api/api/checkers/tcp_port.py @@ -1,11 +1,42 @@ -from core.coretypes import Response +from core.coretypes import Response, PortResponse, ResponseStatus, ErrorPayload, ErrorCodes from .base import BaseChecker +import socket class TCPPortChecker(BaseChecker): - def __init__(self, target: str): + def __init__(self, target: str, port: int): + self.port = port super().__init__(target) def check(self) -> Response: - pass + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + # 2 seconds timeout... + sock.settimeout(2) + + try: + res = sock.connect_ex((self.target, self.port)) + except socket.gaierror: + return Response( + status=ResponseStatus.ERROR, + payload=ErrorPayload( + message="Invalid hostname", + code=ErrorCodes.InvalidHostname + ), + node=self.node_info + ) + if res == 0: + sock.close() + return Response( + status=ResponseStatus.OK, + payload=PortResponse(open=True), + node=self.node_info + ) + sock.close() + return Response( + status=ResponseStatus.OK, + payload=PortResponse(open=False), + node=self.node_info + ) + + diff --git a/apps/core/core/coretypes.py b/apps/core/core/coretypes.py index a8d89dd..9aabf66 100644 --- a/apps/core/core/coretypes.py +++ b/apps/core/core/coretypes.py @@ -14,8 +14,7 @@ class ResponseStatus(str, Enum): class ErrorCodes(IntEnum): ConnectError = 1 ICMPHostNotAlive = 2 - TCPPortClosed = 3 - UDPPortClosed = 4 + InvalidHostname = 3 @dataclass @@ -46,6 +45,11 @@ class APINodeInfo: location: str +@dataclass +class PortResponse(Payload): + open: bool + + @dataclass class Response: status: ResponseStatus diff --git a/apps/core/pyproject.toml b/apps/core/pyproject.toml index 8173bbe..4d44170 100644 --- a/apps/core/pyproject.toml +++ b/apps/core/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "core" -version = "0.6.0" +version = "0.7.0" description = "Types and other core functionality" authors = ["kiriharu "]