134 lines
4.6 KiB
Python
134 lines
4.6 KiB
Python
from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
from dotenv import load_dotenv
|
|
import socket
|
|
import json
|
|
import threading
|
|
import logging
|
|
import win32serviceutil
|
|
import win32service
|
|
import win32event
|
|
import servicemanager
|
|
import os
|
|
import sys
|
|
|
|
# Load environment variables from .env file
|
|
load_dotenv()
|
|
|
|
HOST = os.getenv("HOST", "0.0.0.0")
|
|
PORT = int(os.getenv("PORT", 8999))
|
|
LOG_FILE = os.path.join(os.path.dirname(__file__), 'hostname_service.log')
|
|
|
|
logging.basicConfig(
|
|
filename=LOG_FILE,
|
|
level=logging.INFO,
|
|
format='%(asctime)s - %(levelname)s - %(message)s'
|
|
)
|
|
|
|
def get_hostname(ip):
|
|
try:
|
|
return socket.gethostbyaddr(ip)[0]
|
|
except socket.herror:
|
|
return None
|
|
|
|
class RequestHandler(BaseHTTPRequestHandler):
|
|
def do_POST(self):
|
|
content_length = int(self.headers.get('Content-Length', 0))
|
|
data = self.rfile.read(content_length)
|
|
try:
|
|
request = json.loads(data.decode())
|
|
logging.info(f"Received POST request: {request}")
|
|
ip = request.get("ip")
|
|
if not ip:
|
|
response = {"error": "Missing 'ip' field"}
|
|
else:
|
|
hostname = get_hostname(ip)
|
|
response = {"hostname": hostname} if hostname else {"error": f"Hostname not found for IP {ip}"}
|
|
except json.JSONDecodeError:
|
|
response = {"error": "Invalid JSON format"}
|
|
except Exception as e:
|
|
logging.exception("Unexpected error during request handling")
|
|
response = {"error": "Internal server error"}
|
|
|
|
response_data = json.dumps(response).encode()
|
|
self.send_response(200)
|
|
self.send_header("Content-Type", "application/json")
|
|
self.send_header("Content-Length", str(len(response_data)))
|
|
self.end_headers()
|
|
self.wfile.write(response_data)
|
|
logging.info(f"Response sent: {response}")
|
|
|
|
def do_GET(self):
|
|
self.send_error(405, "Method Not Allowed")
|
|
logging.warning("Rejected GET request")
|
|
|
|
def do_PUT(self):
|
|
self.send_error(405, "Method Not Allowed")
|
|
logging.warning("Rejected PUT request")
|
|
|
|
def do_DELETE(self):
|
|
self.send_error(405, "Method Not Allowed")
|
|
logging.warning("Rejected DELETE request")
|
|
|
|
def log_message(self, format, *args):
|
|
return # Silence default stdout logging
|
|
|
|
class HostnameService(win32serviceutil.ServiceFramework):
|
|
_svc_name_ = "HostnameHTTPService"
|
|
_svc_display_name_ = "Hostname HTTP Resolver Service"
|
|
_svc_description_ = "HTTP service that resolves hostnames from IPs on port 8999 (POST only)."
|
|
|
|
def __init__(self, args):
|
|
super().__init__(args)
|
|
self.stop_event = win32event.CreateEvent(None, 0, 0, None)
|
|
self.is_running = True
|
|
self.server_thread = None
|
|
self.httpd = None
|
|
|
|
def SvcStop(self):
|
|
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
|
|
self.is_running = False
|
|
logging.info("Service stopping...")
|
|
if self.httpd:
|
|
self.httpd.shutdown()
|
|
win32event.SetEvent(self.stop_event)
|
|
if self.server_thread and self.server_thread.is_alive():
|
|
self.server_thread.join()
|
|
logging.info("HTTP server stopped.")
|
|
|
|
def SvcDoRun(self):
|
|
logging.info("Service starting...")
|
|
self.server_thread = threading.Thread(target=self.run_server)
|
|
self.server_thread.start()
|
|
win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE)
|
|
logging.info("Service stopped.")
|
|
|
|
def run_server(self):
|
|
try:
|
|
self.httpd = HTTPServer((HOST, PORT), RequestHandler)
|
|
logging.info(f"HTTP server started on port {PORT}")
|
|
self.httpd.serve_forever()
|
|
except Exception as e:
|
|
logging.exception("Server failed: %s", str(e))
|
|
|
|
if __name__ == '__main__':
|
|
try:
|
|
if len(sys.argv) == 1:
|
|
win32serviceutil.HandleCommandLine(HostnameService)
|
|
else:
|
|
if sys.argv[1] == "run":
|
|
# Allow running standalone (not as service)
|
|
logging.info("Running in standalone HTTP mode.")
|
|
httpd = HTTPServer((HOST, PORT), RequestHandler)
|
|
print(f"Listening on port {PORT}...")
|
|
try:
|
|
httpd.serve_forever()
|
|
except KeyboardInterrupt:
|
|
print("Shutting down...")
|
|
logging.info("HTTP server shut down by user.")
|
|
httpd.shutdown()
|
|
else:
|
|
win32serviceutil.HandleCommandLine(HostnameService)
|
|
except Exception as e:
|
|
logging.exception("Service startup error: %s", str(e))
|
|
sys.exit(1)
|