import DeleteIcon from "@mui/icons-material/Delete"; import { Alert, Button, Card, CardActions, CardContent, IconButton, Tooltip, Typography, } from "@mui/material"; import Grid from "@mui/material/Grid2"; import React, { PropsWithChildren } from "react"; import { NatEntry } from "../../api/NetworksApi"; import { ServerApi } from "../../api/ServerApi"; import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider"; import { IPInput } from "./IPInput"; import { PortInput } from "./PortInput"; import { RadioGroupInput } from "./RadioGroupInput"; import { SelectInput } from "./SelectInput"; import { TextInput } from "./TextInput"; export function NetNatConfiguration(p: { editable: boolean; nat: NatEntry[]; nicsList: string[]; onChange?: (nat: NatEntry[]) => void; version: 4 | 6; }): React.ReactElement { const confirm = useConfirm(); const addEntry = () => { p.nat.push({ host_ip: { type: "ip", ip: p.version === 4 ? "10.0.0.1" : "fd00::", }, host_port: { type: "single", port: 80 }, guest_ip: p.version === 4 ? "10.0.0.100" : "fd00::", guest_port: 10, protocol: "TCP", }); p.onChange?.(p.nat); }; const onDelete = async (idx: number) => { if (!(await confirm("Do you really want to delete this entry?"))) return; p.nat.splice(idx, 1); p.onChange?.(p.nat); }; return ( <> {p.nat.map((e, num) => ( p.onChange?.(p.nat)} onDelete={() => onDelete(num)} /> ))} {p.nat.length === 0 && ( You have not set any NAT entry yet. )} {p.editable && } ); } function NatEntryForm(p: { editable: boolean; version: 4 | 6; entry: NatEntry; onChange?: () => void; onDelete: () => void; nicsList: string[]; }): React.ReactElement { const guestPortEnd = p.entry.host_port.type === "range" ? p.entry.host_port.end - p.entry.host_port.start + p.entry.guest_port : undefined; return ( { p.entry.protocol = v as any; p.onChange?.(); }} /> { p.entry.comment = v; p.onChange?.(); }} size={ServerApi.Config.constraints.net_nat_comment_size} /> {/* Host conf */} { p.entry.host_ip.type = v as any; p.onChange?.(); }} /> {p.entry.host_ip.type === "ip" && ( { if (p.entry.host_ip.type === "ip") p.entry.host_ip.ip = v!; p.onChange?.(); }} /> )} {p.entry.host_ip.type === "interface" && ( <> {p.editable && ( Warning! All IP addresses may not be inferred on reboot due to the fact that the network hook might be executed before the network interfaces are fully configured. This might lead to incomplete ports exposition! )} { return { value: n, }; })} onValueChange={(v) => { if (p.entry.host_ip.type === "interface") p.entry.host_ip.name = v!; p.onChange?.(); }} /> )} { p.entry.guest_ip = v!; p.onChange?.(); }} /> { p.entry.host_port.type = v as any; p.onChange?.(); }} /> {p.entry.host_port.type === "single" && ( { if (p.entry.host_port.type === "single") p.entry.host_port.port = v!; p.onChange?.(); }} /> )} {p.entry.host_port.type === "range" && (
{ if (p.entry.host_port.type === "range") p.entry.host_port.start = v!; p.onChange?.(); }} /> { if (p.entry.host_port.type === "range") p.entry.host_port.end = v!; p.onChange?.(); }} />
)}
{ p.entry.guest_port = v!; p.onChange?.(); }} /> {guestPortEnd && } {guestPortEnd && ( { p.entry.guest_port = v!; p.onChange?.(); }} /> )}
{p.editable && ( )}
); } function NATEntryProp( p: PropsWithChildren<{ label?: string }> ): React.ReactElement { return ( {p.label && ( {p.label} )} {p.children} ); } function PortSpacer(): React.ReactElement { return ; }