#!/usr/bin/env python3 """ 정상 사용자 시뮬레이터. 공격 전/중/후에 주기적으로 평범한 HTTP/1.1 GET 을 던져서 응답 성공 / 지연(latency) / 실패(타임아웃·거부)를 타임스탬프와 함께 기록한다. DoS 입증 자료: "공격 시작 시점부터 정상 요청이 실패/지연되기 시작" 을 보여줌. 사용 예: python victim_probe.py --host 127.0.0.1 --port 10080 --path / --interval 0.5 --duration 90 --timeout 3 공격 스크립트(h2bomb_poc.py)는 이 프로브가 도는 도중에 별도 창에서 실행. """ import argparse import http.client import socket import time from datetime import datetime def probe_once(host, port, path, timeout): start = time.monotonic() conn = None try: conn = http.client.HTTPConnection(host, port, timeout=timeout) conn.request("GET", path, headers={"Connection": "close", "User-Agent": "victim-probe/1.0"}) resp = conn.getresponse() resp.read() latency = (time.monotonic() - start) * 1000.0 return ("OK", resp.status, latency, "") except socket.timeout: latency = (time.monotonic() - start) * 1000.0 return ("TIMEOUT", 0, latency, "read/connect timed out") except ConnectionRefusedError as e: latency = (time.monotonic() - start) * 1000.0 return ("REFUSED", 0, latency, str(e)) except (ConnectionResetError, http.client.RemoteDisconnected) as e: latency = (time.monotonic() - start) * 1000.0 return ("RESET", 0, latency, str(e)) except OSError as e: latency = (time.monotonic() - start) * 1000.0 return ("ERROR", 0, latency, str(e)) finally: if conn is not None: try: conn.close() except OSError: pass def main(): p = argparse.ArgumentParser(description="정상 사용자 요청 프로브 (DoS 영향 측정)") p.add_argument("--host", default="127.0.0.1") p.add_argument("--port", type=int, default=10080) p.add_argument("--path", default="/") p.add_argument("--interval", type=float, default=0.5, help="요청 간격(초)") p.add_argument("--duration", type=float, default=90.0, help="총 측정 시간(초)") p.add_argument("--timeout", type=float, default=3.0, help="요청당 타임아웃(초)") args = p.parse_args() print(f"# probe target=http://{args.host}:{args.port}{args.path} " f"interval={args.interval}s timeout={args.timeout}s duration={args.duration}s") print(f"# {'time':<12} {'result':<8} {'status':<6} {'latency_ms':<10} note") end = time.monotonic() + args.duration n = ok = fail = 0 lat_sum = 0.0 while time.monotonic() < end: cycle_start = time.monotonic() result, status, latency, note = probe_once(args.host, args.port, args.path, args.timeout) ts = datetime.now().strftime("%H:%M:%S.%f")[:-3] n += 1 if result == "OK" and 200 <= status < 500: ok += 1 lat_sum += latency else: fail += 1 print(f"{ts:<12} {result:<8} {status:<6} {latency:>9.1f} {note}", flush=True) # 간격 유지 sleep_left = args.interval - (time.monotonic() - cycle_start) if sleep_left > 0: time.sleep(sleep_left) avg_ok = (lat_sum / ok) if ok else 0.0 print(f"# summary total={n} ok={ok} fail={fail} " f"fail_rate={100.0*fail/max(1,n):.1f}% avg_ok_latency_ms={avg_ok:.1f}") if __name__ == "__main__": main()