/**
* Network security tools
*/
import {
NmapScanInput,
NmapDiscoverInput,
MasscanInput,
NetdiscoverInput,
TcpdumpInput,
TsharkInput,
} from "../schemas/network.schemas.js";
import { ToolResult } from "../types.js";
import { executeCommand } from "../utils/executor.js";
import { formatExecutionResult, formatErrorMessage } from "../utils/formatter.js";
import { validateTarget, validateCIDR, validatePortRange, validateInterface } from "../utils/validator.js";
import { TOOL_PATHS } from "../constants.js";
/**
* Nmap port scanning
*/
export async function nmapScan(input: NmapScanInput): Promise<ToolResult> {
// Validate target
if (!validateTarget(input.target)) {
return formatErrorMessage(
"Invalid target format",
`Target '${input.target}' must be a valid IP, CIDR, or hostname`
);
}
// Validate ports if specified
if (input.ports && !validatePortRange(input.ports)) {
return formatErrorMessage(
"Invalid port range",
`Port range '${input.ports}' is not valid`
);
}
// Build nmap command arguments
const args: string[] = [];
// Scan type
switch (input.scan_type) {
case "tcp_syn":
args.push("-sS");
break;
case "tcp_connect":
args.push("-sT");
break;
case "udp":
args.push("-sU");
break;
case "ack":
args.push("-sA");
break;
case "null":
args.push("-sN");
break;
case "fin":
args.push("-sF");
break;
case "xmas":
args.push("-sX");
break;
}
// Timing
const timingMap: Record<string, string> = {
paranoid: "-T0",
sneaky: "-T1",
polite: "-T2",
normal: "-T3",
aggressive: "-T4",
insane: "-T5",
};
args.push(timingMap[input.timing]!);
// Ports
if (input.ports) {
if (input.ports === "-") {
args.push("-p-");
} else {
args.push("-p", input.ports);
}
}
// OS detection
if (input.os_detection) {
args.push("-O");
}
// Service version detection
if (input.service_version) {
args.push("-sV");
}
// Script scan
if (input.script_scan) {
args.push("--script", input.script_scan);
}
// Aggressive scan
if (input.aggressive) {
args.push("-A");
}
// Output format
if (input.output_format === "xml") {
args.push("-oX", "-");
} else if (input.output_format === "grepable") {
args.push("-oG", "-");
}
// Target
args.push(input.target);
// Execute
const result = await executeCommand(TOOL_PATHS.nmap || "nmap", args, {
timeout: input.timeout * 1000,
});
return formatExecutionResult(result);
}
/**
* Nmap host discovery
*/
export async function nmapDiscover(input: NmapDiscoverInput): Promise<ToolResult> {
// Validate network
if (!validateCIDR(input.network)) {
return formatErrorMessage(
"Invalid network range",
`Network '${input.network}' must be in CIDR notation (e.g., '192.168.1.0/24')`
);
}
const args: string[] = [];
// Discovery method
switch (input.method) {
case "ping":
args.push("-sn"); // Ping scan
break;
case "arp":
args.push("-PR"); // ARP scan
break;
case "tcp":
args.push("-PS"); // TCP SYN discovery
break;
case "udp":
args.push("-PU"); // UDP discovery
break;
case "icmp":
args.push("-PE"); // ICMP echo discovery
break;
}
args.push(input.network);
const result = await executeCommand(TOOL_PATHS.nmap || "nmap", args, {
timeout: input.timeout * 1000,
});
return formatExecutionResult(result);
}
/**
* Masscan high-speed port scanner
*/
export async function masscan(input: MasscanInput): Promise<ToolResult> {
// Validate target
if (!validateTarget(input.target) && !validateCIDR(input.target)) {
return formatErrorMessage(
"Invalid target format",
`Target '${input.target}' must be a valid IP, range, or CIDR`
);
}
// Validate ports
if (!validatePortRange(input.ports)) {
return formatErrorMessage(
"Invalid port range",
`Port range '${input.ports}' is not valid`
);
}
const args: string[] = [];
// Ports
args.push("-p", input.ports);
// Rate
args.push("--rate", String(input.rate));
// Banners
if (input.banners) {
args.push("--banners");
}
// Target
args.push(input.target);
const result = await executeCommand(TOOL_PATHS.masscan || "masscan", args, {
timeout: input.timeout * 1000,
});
return formatExecutionResult(result);
}
/**
* Netdiscover ARP reconnaissance
*/
export async function netdiscover(input: NetdiscoverInput): Promise<ToolResult> {
// Validate interface if specified
if (input.interface && !validateInterface(input.interface)) {
return formatErrorMessage(
"Invalid interface",
`Interface '${input.interface}' is not a valid network interface name`
);
}
// Validate range if specified
if (input.range && !validateCIDR(input.range)) {
return formatErrorMessage(
"Invalid range",
`Range '${input.range}' must be in CIDR notation`
);
}
const args: string[] = [];
// Interface
if (input.interface) {
args.push("-i", input.interface);
}
// Range
if (input.range) {
args.push("-r", input.range);
}
// Passive mode
if (input.passive) {
args.push("-p");
}
const result = await executeCommand("netdiscover", args, {
timeout: input.timeout * 1000,
});
return formatExecutionResult(result);
}
/**
* Tcpdump packet capture
*/
export async function tcpdump(input: TcpdumpInput): Promise<ToolResult> {
// Validate interface
if (!validateInterface(input.interface) && input.interface !== "any") {
return formatErrorMessage(
"Invalid interface",
`Interface '${input.interface}' is not valid. Use 'any' for all interfaces`
);
}
const args: string[] = [];
// Interface
args.push("-i", input.interface);
// Verbose
if (input.verbose) {
args.push("-v");
}
// Count
if (input.count) {
args.push("-c", String(input.count));
}
// Output file
if (input.output_file) {
args.push("-w", input.output_file);
}
// Filter (must be last)
if (input.filter) {
args.push(input.filter);
}
// Calculate timeout
const timeout = input.duration ? input.duration * 1000 : 60000;
const result = await executeCommand("tcpdump", args, { timeout });
return formatExecutionResult(result);
}
/**
* Tshark packet capture and analysis
*/
export async function tshark(input: TsharkInput): Promise<ToolResult> {
// Validate interface
if (!validateInterface(input.interface) && input.interface !== "any") {
return formatErrorMessage(
"Invalid interface",
`Interface '${input.interface}' is not valid`
);
}
const args: string[] = [];
// Interface
args.push("-i", input.interface);
// Count
if (input.count) {
args.push("-c", String(input.count));
}
// Duration
if (input.duration) {
args.push("-a", `duration:${input.duration}`);
}
// Filter
if (input.filter) {
args.push("-Y", input.filter);
}
// Fields
if (input.fields && input.fields.length > 0) {
args.push("-T", "fields");
for (const field of input.fields) {
args.push("-e", field);
}
}
// Output format
if (input.output_format === "json") {
args.push("-T", "json");
} else if (input.output_format === "xml") {
args.push("-T", "pdml");
}
const timeout = input.duration ? input.duration * 1000 + 5000 : 65000;
const result = await executeCommand("tshark", args, { timeout });
return formatExecutionResult(result);
}