wraith/src/components/tools/SubnetCalc.vue
Vantz Stockwell b3f56a2729
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 7s
feat: Tools R2 — DNS, Whois, Bandwidth, Subnet Calculator
4 new tools with full backend + popup UIs:

DNS Lookup:
- dig/nslookup/host fallback chain on remote host
- Record type selector (A, AAAA, MX, NS, TXT, CNAME, SOA, SRV, PTR)

Whois:
- Remote whois query, first 80 lines
- Works for domains and IP addresses

Bandwidth Test (2 modes):
- iperf3: LAN speed test between remote host and iperf server
- Internet: speedtest-cli / curl-based Cloudflare test fallback

Subnet Calculator:
- Pure Rust, no SSH needed
- CIDR input with quick-select buttons (/8 through /32)
- Displays: network, broadcast, netmask, wildcard, host range,
  total/usable hosts, class, private/public

Tools menu now has 11 items across 3 sections.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:12:11 -04:00

50 lines
2.8 KiB
Vue

<template>
<div class="flex flex-col h-full p-4 gap-4">
<div class="flex items-center gap-2">
<input v-model="cidr" type="text" placeholder="192.168.1.0/24" class="px-3 py-1.5 text-sm rounded bg-[#161b22] border border-[#30363d] text-[#e0e0e0] outline-none focus:border-[#58a6ff] w-48 font-mono" @keydown.enter="calc" />
<button class="px-4 py-1.5 text-sm font-bold rounded bg-[#58a6ff] text-black cursor-pointer" @click="calc">Calculate</button>
<div class="flex items-center gap-1 ml-2">
<button v-for="quick in ['/8','/16','/24','/25','/26','/27','/28','/29','/30','/32']" :key="quick"
class="px-1.5 py-0.5 text-[10px] rounded bg-[#21262d] text-[#8b949e] hover:text-white hover:bg-[#30363d] cursor-pointer"
@click="cidr = cidr.replace(/\/\d+$/, '') + quick; calc()"
>{{ quick }}</button>
</div>
</div>
<div v-if="info" class="grid grid-cols-2 gap-x-6 gap-y-2 text-xs">
<div><span class="text-[#8b949e]">CIDR:</span> <span class="font-mono">{{ info.cidr }}</span></div>
<div><span class="text-[#8b949e]">Class:</span> {{ info.class }} <span v-if="info.isPrivate" class="text-[#3fb950]">(Private)</span></div>
<div><span class="text-[#8b949e]">Network:</span> <span class="font-mono">{{ info.network }}</span></div>
<div><span class="text-[#8b949e]">Broadcast:</span> <span class="font-mono">{{ info.broadcast }}</span></div>
<div><span class="text-[#8b949e]">Netmask:</span> <span class="font-mono">{{ info.netmask }}</span></div>
<div><span class="text-[#8b949e]">Wildcard:</span> <span class="font-mono">{{ info.wildcard }}</span></div>
<div><span class="text-[#8b949e]">First Host:</span> <span class="font-mono">{{ info.firstHost }}</span></div>
<div><span class="text-[#8b949e]">Last Host:</span> <span class="font-mono">{{ info.lastHost }}</span></div>
<div><span class="text-[#8b949e]">Total Hosts:</span> {{ info.totalHosts.toLocaleString() }}</div>
<div><span class="text-[#8b949e]">Usable Hosts:</span> {{ info.usableHosts.toLocaleString() }}</div>
<div><span class="text-[#8b949e]">Prefix Length:</span> /{{ info.prefixLength }}</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { invoke } from "@tauri-apps/api/core";
const cidr = ref("192.168.1.0/24");
interface SubnetInfo {
cidr: string; network: string; broadcast: string; netmask: string; wildcard: string;
firstHost: string; lastHost: string; totalHosts: number; usableHosts: number;
prefixLength: number; class: string; isPrivate: boolean;
}
const info = ref<SubnetInfo | null>(null);
async function calc(): Promise<void> {
if (!cidr.value) return;
try { info.value = await invoke<SubnetInfo>("tool_subnet_calc", { cidr: cidr.value }); }
catch (err) { alert(err); }
}
</script>