#!/usr/bin/env python3
"""
vuln_app_fixed.py - "HomeLand Controller" (ban DA SUA)
========================================================
Cung mot tinh nang nhu vuln_app.py (PING <dia_chi>), nhung sua dung 2 cach
tieu chuan de chong command injection:

  1. Kiem tra dau vao bang allowlist (chi cho IPv4 hop le), tu choi thang
     moi ky tu la hoac khong thuoc dinh dang mong doi.
  2. Goi subprocess voi LIST tham so va shell=False: he dieu hanh chay
     dung "ping", "-c", "1", "<dia_chi>" nhu bon doi so rieng, KHONG dua
     qua shell nen khong co cho noi them lenh thu hai.

Chay thu voi cung payload da khai thac vuln_app.py de thay no bi tu choi.
"""
import argparse
import ipaddress
import socket
import platform
import subprocess

PORT_DEFAULT = 9500


def is_safe_ipv4(text: str) -> bool:
    try:
        ipaddress.IPv4Address(text)
        return True
    except ValueError:
        return False


def handle(payload: str) -> str:
    payload = payload.strip()
    if not payload.upper().startswith("PING "):
        return "LOI: chi ho tro lenh PING <dia_chi>\n"
    target = payload[5:].strip()
    if not is_safe_ipv4(target):
        return f"TU CHOI: '{target}' khong phai dia chi IPv4 hop le. Khong chay lenh gi ca.\n"
    try:
        # shell=False + list tham so: khong co "shell" de noi them lenh
        flags = ["-n", "1", "-w", "1000"] if platform.system() == "Windows" else ["-c", "1", "-t", "1"]
        out = subprocess.run(["ping", *flags, target],
                              shell=False, capture_output=True, text=True, timeout=5)
        return (out.stdout + out.stderr) or "(khong co ket qua)\n"
    except Exception as e:  # noqa: BLE001 - demo day hoc
        return f"LOI: {e}\n"


def main():
    ap = argparse.ArgumentParser(description="HomeLand Controller (ban DA SUA)")
    ap.add_argument("--port", type=int, default=PORT_DEFAULT)
    ap.add_argument("--lan", action="store_true")
    args = ap.parse_args()
    bind_ip = "0.0.0.0" if args.lan else "127.0.0.1"

    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind((bind_ip, args.port))
        s.listen(5)
        print(f"[HomeLand - DA SUA] dang lang nghe {bind_ip}:{args.port}")
        while True:
            conn, addr = s.accept()
            with conn:
                data = conn.recv(4096).decode("utf-8", "replace")
                print(f"[ket noi tu {addr}] nhan: {data!r}")
                conn.sendall(handle(data).encode("utf-8", "replace"))


if __name__ == "__main__":
    main()
