Public/Network/New-VergeNetworkRule.ps1
|
function New-VergeNetworkRule { <# .SYNOPSIS Creates a new firewall rule on a VergeOS virtual network. .DESCRIPTION New-VergeNetworkRule creates a new firewall rule with the specified configuration. After creating rules, use Invoke-VergeNetworkApply to apply the changes. .PARAMETER Network The name or key of the network to create the rule on. .PARAMETER NetworkObject A network object from Get-VergeNetwork. Accepts pipeline input. .PARAMETER Name The name of the new rule. Must be unique within the network. .PARAMETER Description An optional description for the rule. .PARAMETER Direction The direction of traffic: Incoming or Outgoing. Default is Incoming. .PARAMETER Action The action to take: Accept, Drop, Reject, Translate, or Route. Default is Accept. .PARAMETER Protocol The protocol to match: TCP, UDP, TCPUDP, ICMP, Any. Default is Any. .PARAMETER SourceIP Source IP filter (e.g., "192.168.0.1", "192.168.1.0/24", or comma-separated list). Special values: vnetself, router, vnet:name, vmnic:vmname.nicname .PARAMETER SourcePorts Source ports or ranges (e.g., "80", "1024-65535", or comma-separated list). .PARAMETER DestinationIP Destination IP filter. Same format as SourceIP. .PARAMETER DestinationPorts Destination ports or ranges (e.g., "443", "80,443", "1000-2000"). .PARAMETER TargetIP Target IP for Translate/Route actions (e.g., "192.168.0.10", "router", "vmnic:vmname.nicname"). .PARAMETER TargetPorts Target ports for port translation. Leave blank if same as destination. .PARAMETER Interface The interface for the rule: Auto, Router, DMZ, WireGuard, Any. Default is Auto. .PARAMETER Enabled Whether the rule is enabled. Default is $true. .PARAMETER Log Enable logging for this rule. .PARAMETER Statistics Enable statistics tracking for this rule. .PARAMETER OrderPosition Position in the rule order. Use "Top", "Bottom", or a number. Default adds to the bottom. .PARAMETER Apply Automatically apply rules after creation. .PARAMETER PassThru Return the created rule object. .PARAMETER Server The VergeOS connection to use. .EXAMPLE New-VergeNetworkRule -Network "External" -Name "Allow HTTPS" -Direction Incoming -Action Accept -Protocol TCP -DestinationPorts "443" Creates a rule to allow incoming HTTPS traffic. .EXAMPLE New-VergeNetworkRule -Network "External" -Name "NAT to Web" -Direction Incoming -Action Translate -Protocol TCP -DestinationPorts "80,443" -TargetIP "192.168.0.10" Creates a NAT rule to translate HTTP/HTTPS to an internal server. .EXAMPLE New-VergeNetworkRule -Network "DMZ" -Name "Block All" -Direction Incoming -Action Drop -Protocol Any -OrderPosition Top Creates a drop-all rule at the top of the rule list. .OUTPUTS None by default. Verge.NetworkRule when -PassThru is specified. .NOTES Rules are not active until Invoke-VergeNetworkApply is called, or use -Apply. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium', DefaultParameterSetName = 'ByNetworkName')] [OutputType([PSCustomObject])] param( [Parameter(Mandatory, Position = 0, ParameterSetName = 'ByNetworkName')] [string]$Network, [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'ByNetworkObject')] [PSTypeName('Verge.Network')] [PSCustomObject]$NetworkObject, [Parameter(Mandatory, Position = 1)] [ValidateNotNullOrEmpty()] [ValidateLength(1, 128)] [string]$Name, [Parameter()] [ValidateLength(0, 2048)] [string]$Description, [Parameter()] [ValidateSet('Incoming', 'Outgoing')] [string]$Direction = 'Incoming', [Parameter()] [ValidateSet('Accept', 'Drop', 'Reject', 'Translate', 'Route')] [string]$Action = 'Accept', [Parameter()] [ValidateSet('TCP', 'UDP', 'TCPUDP', 'ICMP', 'Any')] [string]$Protocol = 'Any', [Parameter()] [string]$SourceIP, [Parameter()] [string]$SourcePorts, [Parameter()] [string]$DestinationIP, [Parameter()] [string]$DestinationPorts, [Parameter()] [string]$TargetIP, [Parameter()] [string]$TargetPorts, [Parameter()] [ValidateSet('Auto', 'Router', 'DMZ', 'WireGuard', 'Any')] [string]$Interface = 'Auto', [Parameter()] [bool]$Enabled = $true, [Parameter()] [switch]$Log, [Parameter()] [switch]$Statistics, [Parameter()] [string]$OrderPosition, [Parameter()] [switch]$Apply, [Parameter()] [switch]$PassThru, [Parameter()] [object]$Server ) begin { # Resolve connection if (-not $Server) { $Server = $script:DefaultConnection } if (-not $Server) { throw [System.InvalidOperationException]::new( 'Not connected to VergeOS. Use Connect-VergeOS to establish a connection.' ) } # Map friendly names to API values $directionMap = @{ 'Incoming' = 'incoming' 'Outgoing' = 'outgoing' } $actionMap = @{ 'Accept' = 'accept' 'Drop' = 'drop' 'Reject' = 'reject' 'Translate' = 'translate' 'Route' = 'route' } $protocolMap = @{ 'TCP' = 'tcp' 'UDP' = 'udp' 'TCPUDP' = 'tcpudp' 'ICMP' = 'icmp' 'Any' = 'any' } $interfaceMap = @{ 'Auto' = 'auto' 'Router' = 'router' 'DMZ' = 'dmz' 'WireGuard' = 'wireguard' 'Any' = 'any' } } process { # Resolve network $targetNetwork = $null if ($PSCmdlet.ParameterSetName -eq 'ByNetworkObject') { $targetNetwork = $NetworkObject } else { if ($Network -match '^\d+$') { $targetNetwork = Get-VergeNetwork -Key ([int]$Network) -Server $Server } else { $targetNetwork = Get-VergeNetwork -Name $Network -Server $Server } } if (-not $targetNetwork) { throw "Network '$Network' not found" } # Build request body $body = @{ vnet = $targetNetwork.Key name = $Name direction = $directionMap[$Direction] action = $actionMap[$Action] protocol = $protocolMap[$Protocol] interface = $interfaceMap[$Interface] enabled = $Enabled } # Add optional parameters if ($Description) { $body['description'] = $Description } if ($SourceIP) { $body['source_ip'] = $SourceIP } if ($SourcePorts) { $body['source_ports'] = $SourcePorts } if ($DestinationIP) { $body['destination_ip'] = $DestinationIP } if ($DestinationPorts) { $body['destination_ports'] = $DestinationPorts } if ($TargetIP) { $body['target_ip'] = $TargetIP } if ($TargetPorts) { $body['target_ports'] = $TargetPorts } if ($Log) { $body['log'] = $true } if ($Statistics) { $body['statistics'] = $true } # Handle order position if ($OrderPosition) { switch ($OrderPosition.ToLower()) { 'top' { $body['pin'] = 'top' } 'bottom' { $body['pin'] = 'bottom' } default { if ($OrderPosition -match '^\d+$') { $body['orderid'] = [int]$OrderPosition } } } } # Build action description $actionDescription = "Create $Action rule '$Name' for $Protocol $Direction traffic" if ($DestinationPorts) { $actionDescription += " on port(s) $DestinationPorts" } if ($PSCmdlet.ShouldProcess($targetNetwork.Name, $actionDescription)) { try { Write-Verbose "Creating rule '$Name' on network '$($targetNetwork.Name)'" $response = Invoke-VergeAPI -Method POST -Endpoint 'vnet_rules' -Body $body -Connection $Server # Get the created rule key $ruleKey = $response.'$key' if (-not $ruleKey -and $response.key) { $ruleKey = $response.key } Write-Verbose "Rule '$Name' created with Key: $ruleKey" # Apply rules if requested if ($Apply) { Write-Verbose "Applying rules on network '$($targetNetwork.Name)'" Invoke-VergeNetworkApply -Network $targetNetwork.Key -Server $Server } if ($PassThru -and $ruleKey) { # Return the created rule Start-Sleep -Milliseconds 500 Get-VergeNetworkRule -Network $targetNetwork.Key -Key $ruleKey -Server $Server } } catch { $errorMessage = $_.Exception.Message if ($errorMessage -match 'already in use') { throw "A rule with the name '$Name' already exists on network '$($targetNetwork.Name)'." } throw "Failed to create rule '$Name': $errorMessage" } } } } |