# coding=utf-8
# *** WARNING: this file was generated by pulumi-language-python. ***
# *** Do not edit by hand unless you're certain you know what you are doing! ***

import builtins as _builtins
import warnings
import sys
import pulumi
import pulumi.runtime
from typing import Any, Mapping, Optional, Sequence, Union, overload
if sys.version_info >= (3, 11):
    from typing import NotRequired, TypedDict, TypeAlias
else:
    from typing_extensions import NotRequired, TypedDict, TypeAlias
from .. import _utilities

__all__ = ['RuleArgs', 'Rule']

@pulumi.input_type
class RuleArgs:
    def __init__(__self__, *,
                 action: pulumi.Input[_builtins.str],
                 rule_index: pulumi.Input[_builtins.int],
                 ruleset: pulumi.Input[_builtins.str],
                 dst_address: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_address_ipv6: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_firewall_group_ids: Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]] = None,
                 dst_network_id: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_network_type: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_port: Optional[pulumi.Input[_builtins.str]] = None,
                 enabled: Optional[pulumi.Input[_builtins.bool]] = None,
                 icmp_typename: Optional[pulumi.Input[_builtins.str]] = None,
                 icmp_v6_typename: Optional[pulumi.Input[_builtins.str]] = None,
                 ip_sec: Optional[pulumi.Input[_builtins.str]] = None,
                 logging: Optional[pulumi.Input[_builtins.bool]] = None,
                 name: Optional[pulumi.Input[_builtins.str]] = None,
                 protocol: Optional[pulumi.Input[_builtins.str]] = None,
                 protocol_v6: Optional[pulumi.Input[_builtins.str]] = None,
                 site: Optional[pulumi.Input[_builtins.str]] = None,
                 src_address: Optional[pulumi.Input[_builtins.str]] = None,
                 src_address_ipv6: Optional[pulumi.Input[_builtins.str]] = None,
                 src_firewall_group_ids: Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]] = None,
                 src_mac: Optional[pulumi.Input[_builtins.str]] = None,
                 src_network_id: Optional[pulumi.Input[_builtins.str]] = None,
                 src_network_type: Optional[pulumi.Input[_builtins.str]] = None,
                 src_port: Optional[pulumi.Input[_builtins.str]] = None,
                 state_established: Optional[pulumi.Input[_builtins.bool]] = None,
                 state_invalid: Optional[pulumi.Input[_builtins.bool]] = None,
                 state_new: Optional[pulumi.Input[_builtins.bool]] = None,
                 state_related: Optional[pulumi.Input[_builtins.bool]] = None):
        """
        The set of arguments for constructing a Rule resource.
        :param pulumi.Input[_builtins.str] action: The action to take when traffic matches this rule. Valid values are:
                 * `accept` - Allow the traffic
                 * `drop` - Silently block the traffic
                 * `reject` - Block the traffic and send an ICMP rejection message
        :param pulumi.Input[_builtins.int] rule_index: The processing order for this rule. Lower numbers are processed first. Custom rules should use:
                 * 2000-2999 for rules processed before auto-generated rules
                 * 4000-4999 for rules processed after auto-generated rules
        :param pulumi.Input[_builtins.str] ruleset: Defines which traffic flow this rule applies to. The format is [NETWORK]_[DIRECTION], where:
                 * NETWORK can be: WAN, LAN, GUEST (or their IPv6 variants WANv6, LANv6, GUESTv6)
                 * DIRECTION can be:
                   * IN - Traffic entering the network
                   * OUT - Traffic leaving the network
                   * LOCAL - Traffic destined for the USG/UDM itself
               
               Examples: WAN_IN (incoming WAN traffic), LAN_OUT (outgoing LAN traffic), GUEST_LOCAL (traffic to Controller from guest network)
        :param pulumi.Input[_builtins.str] dst_address: The destination IPv4 address or network in CIDR notation (e.g., '192.168.1.10' or '192.168.0.0/24'). The format must match dst_network_type - use a single IP for ADDRv4 or CIDR for NETv4.
        :param pulumi.Input[_builtins.str] dst_address_ipv6: The destination IPv6 address or network in CIDR notation (e.g., '2001:db8::1' or '2001:db8::/64'). Used for IPv6 firewall rules.
        :param pulumi.Input[Sequence[pulumi.Input[_builtins.str]]] dst_firewall_group_ids: A list of firewall group IDs to use as destinations. Groups can contain IP addresses, networks, or port numbers. This allows you to create reusable sets of addresses/ports and reference them in multiple rules.
        :param pulumi.Input[_builtins.str] dst_network_id: The ID of the destination network this rule applies to. This can be found in the URL when viewing the network in the UniFi controller.
        :param pulumi.Input[_builtins.str] dst_network_type: The type of destination network address. Valid values are:
                 * `ADDRv4` - Single IPv4 address
                 * `NETv4` - IPv4 network in CIDR notation
        :param pulumi.Input[_builtins.str] dst_port: The destination port(s) for this rule. Can be:
                 * A single port number (e.g., '80')
                 * A port range (e.g., '8000:8080')
                 * A list of ports/ranges separated by commas
        :param pulumi.Input[_builtins.bool] enabled: Whether this firewall rule is active (true) or disabled (false). Defaults to true.
        :param pulumi.Input[_builtins.str] icmp_typename: The ICMP type name when protocol is set to 'icmp'. Common values include:
                 * `echo-request` - ICMP ping requests
                 * `echo-reply` - ICMP ping replies
                 * `destination-unreachable` - Host/network unreachable messages
                 * `time-exceeded` - TTL exceeded messages (traceroute)
        :param pulumi.Input[_builtins.str] icmp_v6_typename: The ICMPv6 type name when protocol_v6 is set to 'ipv6-icmp'. Common values (not all are listed) include:
                 * `echo-request` - IPv6 ping requests
                 * `echo-reply` - IPv6 ping replies
                 * `neighbor-solicitation` - IPv6 neighbor discovery
                 * `neighbor-advertisement` - IPv6 neighbor announcements
                 * `destination-unreachable` - Host/network unreachable messages
                 * `packet-too-big` - Path MTU discovery messages
        :param pulumi.Input[_builtins.str] ip_sec: Specify whether the rule matches on IPsec packets. Can be one of `match-ipsec` or `match-none`.
        :param pulumi.Input[_builtins.bool] logging: Enable logging for the firewall rule.
        :param pulumi.Input[_builtins.str] name: A friendly name for the firewall rule. This helps identify the rule's purpose in the UniFi controller UI.
        :param pulumi.Input[_builtins.str] protocol: The IPv4 protocol this rule applies to. Common values (not all are listed) include:
                 * `all` - Match all protocols
                 * `tcp` - TCP traffic only (e.g., web, email)
                 * `udp` - UDP traffic only (e.g., DNS, VoIP)
                 * `tcp_udp` - Both TCP and UDP
                 * `icmp` - ICMP traffic (ping, traceroute)
                 * Protocol numbers (1-255) for other protocols
               
               Examples:
                 * Use 'tcp' for web server rules (ports 80, 443)
                 * Use 'udp' for VoIP or gaming traffic
                 * Use 'all' for general network access rules
        :param pulumi.Input[_builtins.str] protocol_v6: The IPv6 protocol this rule applies to. Similar to 'protocol' but for IPv6 traffic. Common values (not all are listed) include:
                 * `all` - Match all protocols
                 * `tcp` - TCP traffic only
                 * `udp` - UDP traffic only
                 * `tcp_udp` - Both TCP and UDP traffic
                 * `ipv6-icmp` - ICMPv6 traffic
        :param pulumi.Input[_builtins.str] site: The name of the UniFi site where the firewall rule should be created. If not specified, the default site will be used.
        :param pulumi.Input[_builtins.str] src_address: The source IPv4 address for the firewall rule.
        :param pulumi.Input[_builtins.str] src_address_ipv6: The source IPv6 address or network in CIDR notation (e.g., '2001:db8::1' or '2001:db8::/64'). Used for IPv6 firewall rules.
        :param pulumi.Input[Sequence[pulumi.Input[_builtins.str]]] src_firewall_group_ids: A list of firewall group IDs to use as sources. Groups can contain:
                 * IP Address Groups - For matching specific IP addresses
                 * Network Groups - For matching entire subnets
                 * Port Groups - For matching specific port numbers
               
               Example uses:
                 * Group of trusted admin IPs for remote access
                 * Group of IoT device networks for isolation
                 * Group of common service ports for allowing specific applications
        :param pulumi.Input[_builtins.str] src_mac: The source MAC address this rule applies to. Use this to create rules that match specific devices regardless of their IP address. Format: 'XX:XX:XX:XX:XX:XX'. MAC addresses are case-insensitive.
        :param pulumi.Input[_builtins.str] src_network_id: The ID of the source network this rule applies to. This can be found in the URL when viewing the network in the UniFi controller, or by using the network's name in the form `[site]/[network_name]`.
        :param pulumi.Input[_builtins.str] src_network_type: The type of source network address. Valid values are:
                 * `ADDRv4` - Single IPv4 address
                 * `NETv4` - IPv4 network in CIDR notation
        :param pulumi.Input[_builtins.str] src_port: The source port(s) for this rule. Can be:
                 * A single port number (e.g., '80')
                 * A port range (e.g., '8000:8080')
                 * A list of ports/ranges separated by commas
        :param pulumi.Input[_builtins.bool] state_established: Match established connections. When enabled:
                 * Rule only applies to packets that are part of an existing connection
                 * Useful for allowing return traffic without creating separate rules
                 * Common in WAN_IN rules to allow responses to outbound connections
               
               Example: Allow established connections from WAN while blocking new incoming connections
        :param pulumi.Input[_builtins.bool] state_invalid: Match where the state is invalid.
        :param pulumi.Input[_builtins.bool] state_new: Match where the state is new.
        :param pulumi.Input[_builtins.bool] state_related: Match where the state is related.
        """
        pulumi.set(__self__, "action", action)
        pulumi.set(__self__, "rule_index", rule_index)
        pulumi.set(__self__, "ruleset", ruleset)
        if dst_address is not None:
            pulumi.set(__self__, "dst_address", dst_address)
        if dst_address_ipv6 is not None:
            pulumi.set(__self__, "dst_address_ipv6", dst_address_ipv6)
        if dst_firewall_group_ids is not None:
            pulumi.set(__self__, "dst_firewall_group_ids", dst_firewall_group_ids)
        if dst_network_id is not None:
            pulumi.set(__self__, "dst_network_id", dst_network_id)
        if dst_network_type is not None:
            pulumi.set(__self__, "dst_network_type", dst_network_type)
        if dst_port is not None:
            pulumi.set(__self__, "dst_port", dst_port)
        if enabled is not None:
            pulumi.set(__self__, "enabled", enabled)
        if icmp_typename is not None:
            pulumi.set(__self__, "icmp_typename", icmp_typename)
        if icmp_v6_typename is not None:
            pulumi.set(__self__, "icmp_v6_typename", icmp_v6_typename)
        if ip_sec is not None:
            pulumi.set(__self__, "ip_sec", ip_sec)
        if logging is not None:
            pulumi.set(__self__, "logging", logging)
        if name is not None:
            pulumi.set(__self__, "name", name)
        if protocol is not None:
            pulumi.set(__self__, "protocol", protocol)
        if protocol_v6 is not None:
            pulumi.set(__self__, "protocol_v6", protocol_v6)
        if site is not None:
            pulumi.set(__self__, "site", site)
        if src_address is not None:
            pulumi.set(__self__, "src_address", src_address)
        if src_address_ipv6 is not None:
            pulumi.set(__self__, "src_address_ipv6", src_address_ipv6)
        if src_firewall_group_ids is not None:
            pulumi.set(__self__, "src_firewall_group_ids", src_firewall_group_ids)
        if src_mac is not None:
            pulumi.set(__self__, "src_mac", src_mac)
        if src_network_id is not None:
            pulumi.set(__self__, "src_network_id", src_network_id)
        if src_network_type is not None:
            pulumi.set(__self__, "src_network_type", src_network_type)
        if src_port is not None:
            pulumi.set(__self__, "src_port", src_port)
        if state_established is not None:
            pulumi.set(__self__, "state_established", state_established)
        if state_invalid is not None:
            pulumi.set(__self__, "state_invalid", state_invalid)
        if state_new is not None:
            pulumi.set(__self__, "state_new", state_new)
        if state_related is not None:
            pulumi.set(__self__, "state_related", state_related)

    @_builtins.property
    @pulumi.getter
    def action(self) -> pulumi.Input[_builtins.str]:
        """
        The action to take when traffic matches this rule. Valid values are:
          * `accept` - Allow the traffic
          * `drop` - Silently block the traffic
          * `reject` - Block the traffic and send an ICMP rejection message
        """
        return pulumi.get(self, "action")

    @action.setter
    def action(self, value: pulumi.Input[_builtins.str]):
        pulumi.set(self, "action", value)

    @_builtins.property
    @pulumi.getter(name="ruleIndex")
    def rule_index(self) -> pulumi.Input[_builtins.int]:
        """
        The processing order for this rule. Lower numbers are processed first. Custom rules should use:
          * 2000-2999 for rules processed before auto-generated rules
          * 4000-4999 for rules processed after auto-generated rules
        """
        return pulumi.get(self, "rule_index")

    @rule_index.setter
    def rule_index(self, value: pulumi.Input[_builtins.int]):
        pulumi.set(self, "rule_index", value)

    @_builtins.property
    @pulumi.getter
    def ruleset(self) -> pulumi.Input[_builtins.str]:
        """
        Defines which traffic flow this rule applies to. The format is [NETWORK]_[DIRECTION], where:
          * NETWORK can be: WAN, LAN, GUEST (or their IPv6 variants WANv6, LANv6, GUESTv6)
          * DIRECTION can be:
            * IN - Traffic entering the network
            * OUT - Traffic leaving the network
            * LOCAL - Traffic destined for the USG/UDM itself

        Examples: WAN_IN (incoming WAN traffic), LAN_OUT (outgoing LAN traffic), GUEST_LOCAL (traffic to Controller from guest network)
        """
        return pulumi.get(self, "ruleset")

    @ruleset.setter
    def ruleset(self, value: pulumi.Input[_builtins.str]):
        pulumi.set(self, "ruleset", value)

    @_builtins.property
    @pulumi.getter(name="dstAddress")
    def dst_address(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The destination IPv4 address or network in CIDR notation (e.g., '192.168.1.10' or '192.168.0.0/24'). The format must match dst_network_type - use a single IP for ADDRv4 or CIDR for NETv4.
        """
        return pulumi.get(self, "dst_address")

    @dst_address.setter
    def dst_address(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "dst_address", value)

    @_builtins.property
    @pulumi.getter(name="dstAddressIpv6")
    def dst_address_ipv6(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The destination IPv6 address or network in CIDR notation (e.g., '2001:db8::1' or '2001:db8::/64'). Used for IPv6 firewall rules.
        """
        return pulumi.get(self, "dst_address_ipv6")

    @dst_address_ipv6.setter
    def dst_address_ipv6(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "dst_address_ipv6", value)

    @_builtins.property
    @pulumi.getter(name="dstFirewallGroupIds")
    def dst_firewall_group_ids(self) -> Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]]:
        """
        A list of firewall group IDs to use as destinations. Groups can contain IP addresses, networks, or port numbers. This allows you to create reusable sets of addresses/ports and reference them in multiple rules.
        """
        return pulumi.get(self, "dst_firewall_group_ids")

    @dst_firewall_group_ids.setter
    def dst_firewall_group_ids(self, value: Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]]):
        pulumi.set(self, "dst_firewall_group_ids", value)

    @_builtins.property
    @pulumi.getter(name="dstNetworkId")
    def dst_network_id(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The ID of the destination network this rule applies to. This can be found in the URL when viewing the network in the UniFi controller.
        """
        return pulumi.get(self, "dst_network_id")

    @dst_network_id.setter
    def dst_network_id(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "dst_network_id", value)

    @_builtins.property
    @pulumi.getter(name="dstNetworkType")
    def dst_network_type(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The type of destination network address. Valid values are:
          * `ADDRv4` - Single IPv4 address
          * `NETv4` - IPv4 network in CIDR notation
        """
        return pulumi.get(self, "dst_network_type")

    @dst_network_type.setter
    def dst_network_type(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "dst_network_type", value)

    @_builtins.property
    @pulumi.getter(name="dstPort")
    def dst_port(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The destination port(s) for this rule. Can be:
          * A single port number (e.g., '80')
          * A port range (e.g., '8000:8080')
          * A list of ports/ranges separated by commas
        """
        return pulumi.get(self, "dst_port")

    @dst_port.setter
    def dst_port(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "dst_port", value)

    @_builtins.property
    @pulumi.getter
    def enabled(self) -> Optional[pulumi.Input[_builtins.bool]]:
        """
        Whether this firewall rule is active (true) or disabled (false). Defaults to true.
        """
        return pulumi.get(self, "enabled")

    @enabled.setter
    def enabled(self, value: Optional[pulumi.Input[_builtins.bool]]):
        pulumi.set(self, "enabled", value)

    @_builtins.property
    @pulumi.getter(name="icmpTypename")
    def icmp_typename(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The ICMP type name when protocol is set to 'icmp'. Common values include:
          * `echo-request` - ICMP ping requests
          * `echo-reply` - ICMP ping replies
          * `destination-unreachable` - Host/network unreachable messages
          * `time-exceeded` - TTL exceeded messages (traceroute)
        """
        return pulumi.get(self, "icmp_typename")

    @icmp_typename.setter
    def icmp_typename(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "icmp_typename", value)

    @_builtins.property
    @pulumi.getter(name="icmpV6Typename")
    def icmp_v6_typename(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The ICMPv6 type name when protocol_v6 is set to 'ipv6-icmp'. Common values (not all are listed) include:
          * `echo-request` - IPv6 ping requests
          * `echo-reply` - IPv6 ping replies
          * `neighbor-solicitation` - IPv6 neighbor discovery
          * `neighbor-advertisement` - IPv6 neighbor announcements
          * `destination-unreachable` - Host/network unreachable messages
          * `packet-too-big` - Path MTU discovery messages
        """
        return pulumi.get(self, "icmp_v6_typename")

    @icmp_v6_typename.setter
    def icmp_v6_typename(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "icmp_v6_typename", value)

    @_builtins.property
    @pulumi.getter(name="ipSec")
    def ip_sec(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        Specify whether the rule matches on IPsec packets. Can be one of `match-ipsec` or `match-none`.
        """
        return pulumi.get(self, "ip_sec")

    @ip_sec.setter
    def ip_sec(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "ip_sec", value)

    @_builtins.property
    @pulumi.getter
    def logging(self) -> Optional[pulumi.Input[_builtins.bool]]:
        """
        Enable logging for the firewall rule.
        """
        return pulumi.get(self, "logging")

    @logging.setter
    def logging(self, value: Optional[pulumi.Input[_builtins.bool]]):
        pulumi.set(self, "logging", value)

    @_builtins.property
    @pulumi.getter
    def name(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        A friendly name for the firewall rule. This helps identify the rule's purpose in the UniFi controller UI.
        """
        return pulumi.get(self, "name")

    @name.setter
    def name(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "name", value)

    @_builtins.property
    @pulumi.getter
    def protocol(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The IPv4 protocol this rule applies to. Common values (not all are listed) include:
          * `all` - Match all protocols
          * `tcp` - TCP traffic only (e.g., web, email)
          * `udp` - UDP traffic only (e.g., DNS, VoIP)
          * `tcp_udp` - Both TCP and UDP
          * `icmp` - ICMP traffic (ping, traceroute)
          * Protocol numbers (1-255) for other protocols

        Examples:
          * Use 'tcp' for web server rules (ports 80, 443)
          * Use 'udp' for VoIP or gaming traffic
          * Use 'all' for general network access rules
        """
        return pulumi.get(self, "protocol")

    @protocol.setter
    def protocol(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "protocol", value)

    @_builtins.property
    @pulumi.getter(name="protocolV6")
    def protocol_v6(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The IPv6 protocol this rule applies to. Similar to 'protocol' but for IPv6 traffic. Common values (not all are listed) include:
          * `all` - Match all protocols
          * `tcp` - TCP traffic only
          * `udp` - UDP traffic only
          * `tcp_udp` - Both TCP and UDP traffic
          * `ipv6-icmp` - ICMPv6 traffic
        """
        return pulumi.get(self, "protocol_v6")

    @protocol_v6.setter
    def protocol_v6(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "protocol_v6", value)

    @_builtins.property
    @pulumi.getter
    def site(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The name of the UniFi site where the firewall rule should be created. If not specified, the default site will be used.
        """
        return pulumi.get(self, "site")

    @site.setter
    def site(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "site", value)

    @_builtins.property
    @pulumi.getter(name="srcAddress")
    def src_address(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The source IPv4 address for the firewall rule.
        """
        return pulumi.get(self, "src_address")

    @src_address.setter
    def src_address(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "src_address", value)

    @_builtins.property
    @pulumi.getter(name="srcAddressIpv6")
    def src_address_ipv6(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The source IPv6 address or network in CIDR notation (e.g., '2001:db8::1' or '2001:db8::/64'). Used for IPv6 firewall rules.
        """
        return pulumi.get(self, "src_address_ipv6")

    @src_address_ipv6.setter
    def src_address_ipv6(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "src_address_ipv6", value)

    @_builtins.property
    @pulumi.getter(name="srcFirewallGroupIds")
    def src_firewall_group_ids(self) -> Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]]:
        """
        A list of firewall group IDs to use as sources. Groups can contain:
          * IP Address Groups - For matching specific IP addresses
          * Network Groups - For matching entire subnets
          * Port Groups - For matching specific port numbers

        Example uses:
          * Group of trusted admin IPs for remote access
          * Group of IoT device networks for isolation
          * Group of common service ports for allowing specific applications
        """
        return pulumi.get(self, "src_firewall_group_ids")

    @src_firewall_group_ids.setter
    def src_firewall_group_ids(self, value: Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]]):
        pulumi.set(self, "src_firewall_group_ids", value)

    @_builtins.property
    @pulumi.getter(name="srcMac")
    def src_mac(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The source MAC address this rule applies to. Use this to create rules that match specific devices regardless of their IP address. Format: 'XX:XX:XX:XX:XX:XX'. MAC addresses are case-insensitive.
        """
        return pulumi.get(self, "src_mac")

    @src_mac.setter
    def src_mac(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "src_mac", value)

    @_builtins.property
    @pulumi.getter(name="srcNetworkId")
    def src_network_id(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The ID of the source network this rule applies to. This can be found in the URL when viewing the network in the UniFi controller, or by using the network's name in the form `[site]/[network_name]`.
        """
        return pulumi.get(self, "src_network_id")

    @src_network_id.setter
    def src_network_id(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "src_network_id", value)

    @_builtins.property
    @pulumi.getter(name="srcNetworkType")
    def src_network_type(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The type of source network address. Valid values are:
          * `ADDRv4` - Single IPv4 address
          * `NETv4` - IPv4 network in CIDR notation
        """
        return pulumi.get(self, "src_network_type")

    @src_network_type.setter
    def src_network_type(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "src_network_type", value)

    @_builtins.property
    @pulumi.getter(name="srcPort")
    def src_port(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The source port(s) for this rule. Can be:
          * A single port number (e.g., '80')
          * A port range (e.g., '8000:8080')
          * A list of ports/ranges separated by commas
        """
        return pulumi.get(self, "src_port")

    @src_port.setter
    def src_port(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "src_port", value)

    @_builtins.property
    @pulumi.getter(name="stateEstablished")
    def state_established(self) -> Optional[pulumi.Input[_builtins.bool]]:
        """
        Match established connections. When enabled:
          * Rule only applies to packets that are part of an existing connection
          * Useful for allowing return traffic without creating separate rules
          * Common in WAN_IN rules to allow responses to outbound connections

        Example: Allow established connections from WAN while blocking new incoming connections
        """
        return pulumi.get(self, "state_established")

    @state_established.setter
    def state_established(self, value: Optional[pulumi.Input[_builtins.bool]]):
        pulumi.set(self, "state_established", value)

    @_builtins.property
    @pulumi.getter(name="stateInvalid")
    def state_invalid(self) -> Optional[pulumi.Input[_builtins.bool]]:
        """
        Match where the state is invalid.
        """
        return pulumi.get(self, "state_invalid")

    @state_invalid.setter
    def state_invalid(self, value: Optional[pulumi.Input[_builtins.bool]]):
        pulumi.set(self, "state_invalid", value)

    @_builtins.property
    @pulumi.getter(name="stateNew")
    def state_new(self) -> Optional[pulumi.Input[_builtins.bool]]:
        """
        Match where the state is new.
        """
        return pulumi.get(self, "state_new")

    @state_new.setter
    def state_new(self, value: Optional[pulumi.Input[_builtins.bool]]):
        pulumi.set(self, "state_new", value)

    @_builtins.property
    @pulumi.getter(name="stateRelated")
    def state_related(self) -> Optional[pulumi.Input[_builtins.bool]]:
        """
        Match where the state is related.
        """
        return pulumi.get(self, "state_related")

    @state_related.setter
    def state_related(self, value: Optional[pulumi.Input[_builtins.bool]]):
        pulumi.set(self, "state_related", value)


@pulumi.input_type
class _RuleState:
    def __init__(__self__, *,
                 action: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_address: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_address_ipv6: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_firewall_group_ids: Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]] = None,
                 dst_network_id: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_network_type: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_port: Optional[pulumi.Input[_builtins.str]] = None,
                 enabled: Optional[pulumi.Input[_builtins.bool]] = None,
                 icmp_typename: Optional[pulumi.Input[_builtins.str]] = None,
                 icmp_v6_typename: Optional[pulumi.Input[_builtins.str]] = None,
                 ip_sec: Optional[pulumi.Input[_builtins.str]] = None,
                 logging: Optional[pulumi.Input[_builtins.bool]] = None,
                 name: Optional[pulumi.Input[_builtins.str]] = None,
                 protocol: Optional[pulumi.Input[_builtins.str]] = None,
                 protocol_v6: Optional[pulumi.Input[_builtins.str]] = None,
                 rule_index: Optional[pulumi.Input[_builtins.int]] = None,
                 ruleset: Optional[pulumi.Input[_builtins.str]] = None,
                 site: Optional[pulumi.Input[_builtins.str]] = None,
                 src_address: Optional[pulumi.Input[_builtins.str]] = None,
                 src_address_ipv6: Optional[pulumi.Input[_builtins.str]] = None,
                 src_firewall_group_ids: Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]] = None,
                 src_mac: Optional[pulumi.Input[_builtins.str]] = None,
                 src_network_id: Optional[pulumi.Input[_builtins.str]] = None,
                 src_network_type: Optional[pulumi.Input[_builtins.str]] = None,
                 src_port: Optional[pulumi.Input[_builtins.str]] = None,
                 state_established: Optional[pulumi.Input[_builtins.bool]] = None,
                 state_invalid: Optional[pulumi.Input[_builtins.bool]] = None,
                 state_new: Optional[pulumi.Input[_builtins.bool]] = None,
                 state_related: Optional[pulumi.Input[_builtins.bool]] = None):
        """
        Input properties used for looking up and filtering Rule resources.
        :param pulumi.Input[_builtins.str] action: The action to take when traffic matches this rule. Valid values are:
                 * `accept` - Allow the traffic
                 * `drop` - Silently block the traffic
                 * `reject` - Block the traffic and send an ICMP rejection message
        :param pulumi.Input[_builtins.str] dst_address: The destination IPv4 address or network in CIDR notation (e.g., '192.168.1.10' or '192.168.0.0/24'). The format must match dst_network_type - use a single IP for ADDRv4 or CIDR for NETv4.
        :param pulumi.Input[_builtins.str] dst_address_ipv6: The destination IPv6 address or network in CIDR notation (e.g., '2001:db8::1' or '2001:db8::/64'). Used for IPv6 firewall rules.
        :param pulumi.Input[Sequence[pulumi.Input[_builtins.str]]] dst_firewall_group_ids: A list of firewall group IDs to use as destinations. Groups can contain IP addresses, networks, or port numbers. This allows you to create reusable sets of addresses/ports and reference them in multiple rules.
        :param pulumi.Input[_builtins.str] dst_network_id: The ID of the destination network this rule applies to. This can be found in the URL when viewing the network in the UniFi controller.
        :param pulumi.Input[_builtins.str] dst_network_type: The type of destination network address. Valid values are:
                 * `ADDRv4` - Single IPv4 address
                 * `NETv4` - IPv4 network in CIDR notation
        :param pulumi.Input[_builtins.str] dst_port: The destination port(s) for this rule. Can be:
                 * A single port number (e.g., '80')
                 * A port range (e.g., '8000:8080')
                 * A list of ports/ranges separated by commas
        :param pulumi.Input[_builtins.bool] enabled: Whether this firewall rule is active (true) or disabled (false). Defaults to true.
        :param pulumi.Input[_builtins.str] icmp_typename: The ICMP type name when protocol is set to 'icmp'. Common values include:
                 * `echo-request` - ICMP ping requests
                 * `echo-reply` - ICMP ping replies
                 * `destination-unreachable` - Host/network unreachable messages
                 * `time-exceeded` - TTL exceeded messages (traceroute)
        :param pulumi.Input[_builtins.str] icmp_v6_typename: The ICMPv6 type name when protocol_v6 is set to 'ipv6-icmp'. Common values (not all are listed) include:
                 * `echo-request` - IPv6 ping requests
                 * `echo-reply` - IPv6 ping replies
                 * `neighbor-solicitation` - IPv6 neighbor discovery
                 * `neighbor-advertisement` - IPv6 neighbor announcements
                 * `destination-unreachable` - Host/network unreachable messages
                 * `packet-too-big` - Path MTU discovery messages
        :param pulumi.Input[_builtins.str] ip_sec: Specify whether the rule matches on IPsec packets. Can be one of `match-ipsec` or `match-none`.
        :param pulumi.Input[_builtins.bool] logging: Enable logging for the firewall rule.
        :param pulumi.Input[_builtins.str] name: A friendly name for the firewall rule. This helps identify the rule's purpose in the UniFi controller UI.
        :param pulumi.Input[_builtins.str] protocol: The IPv4 protocol this rule applies to. Common values (not all are listed) include:
                 * `all` - Match all protocols
                 * `tcp` - TCP traffic only (e.g., web, email)
                 * `udp` - UDP traffic only (e.g., DNS, VoIP)
                 * `tcp_udp` - Both TCP and UDP
                 * `icmp` - ICMP traffic (ping, traceroute)
                 * Protocol numbers (1-255) for other protocols
               
               Examples:
                 * Use 'tcp' for web server rules (ports 80, 443)
                 * Use 'udp' for VoIP or gaming traffic
                 * Use 'all' for general network access rules
        :param pulumi.Input[_builtins.str] protocol_v6: The IPv6 protocol this rule applies to. Similar to 'protocol' but for IPv6 traffic. Common values (not all are listed) include:
                 * `all` - Match all protocols
                 * `tcp` - TCP traffic only
                 * `udp` - UDP traffic only
                 * `tcp_udp` - Both TCP and UDP traffic
                 * `ipv6-icmp` - ICMPv6 traffic
        :param pulumi.Input[_builtins.int] rule_index: The processing order for this rule. Lower numbers are processed first. Custom rules should use:
                 * 2000-2999 for rules processed before auto-generated rules
                 * 4000-4999 for rules processed after auto-generated rules
        :param pulumi.Input[_builtins.str] ruleset: Defines which traffic flow this rule applies to. The format is [NETWORK]_[DIRECTION], where:
                 * NETWORK can be: WAN, LAN, GUEST (or their IPv6 variants WANv6, LANv6, GUESTv6)
                 * DIRECTION can be:
                   * IN - Traffic entering the network
                   * OUT - Traffic leaving the network
                   * LOCAL - Traffic destined for the USG/UDM itself
               
               Examples: WAN_IN (incoming WAN traffic), LAN_OUT (outgoing LAN traffic), GUEST_LOCAL (traffic to Controller from guest network)
        :param pulumi.Input[_builtins.str] site: The name of the UniFi site where the firewall rule should be created. If not specified, the default site will be used.
        :param pulumi.Input[_builtins.str] src_address: The source IPv4 address for the firewall rule.
        :param pulumi.Input[_builtins.str] src_address_ipv6: The source IPv6 address or network in CIDR notation (e.g., '2001:db8::1' or '2001:db8::/64'). Used for IPv6 firewall rules.
        :param pulumi.Input[Sequence[pulumi.Input[_builtins.str]]] src_firewall_group_ids: A list of firewall group IDs to use as sources. Groups can contain:
                 * IP Address Groups - For matching specific IP addresses
                 * Network Groups - For matching entire subnets
                 * Port Groups - For matching specific port numbers
               
               Example uses:
                 * Group of trusted admin IPs for remote access
                 * Group of IoT device networks for isolation
                 * Group of common service ports for allowing specific applications
        :param pulumi.Input[_builtins.str] src_mac: The source MAC address this rule applies to. Use this to create rules that match specific devices regardless of their IP address. Format: 'XX:XX:XX:XX:XX:XX'. MAC addresses are case-insensitive.
        :param pulumi.Input[_builtins.str] src_network_id: The ID of the source network this rule applies to. This can be found in the URL when viewing the network in the UniFi controller, or by using the network's name in the form `[site]/[network_name]`.
        :param pulumi.Input[_builtins.str] src_network_type: The type of source network address. Valid values are:
                 * `ADDRv4` - Single IPv4 address
                 * `NETv4` - IPv4 network in CIDR notation
        :param pulumi.Input[_builtins.str] src_port: The source port(s) for this rule. Can be:
                 * A single port number (e.g., '80')
                 * A port range (e.g., '8000:8080')
                 * A list of ports/ranges separated by commas
        :param pulumi.Input[_builtins.bool] state_established: Match established connections. When enabled:
                 * Rule only applies to packets that are part of an existing connection
                 * Useful for allowing return traffic without creating separate rules
                 * Common in WAN_IN rules to allow responses to outbound connections
               
               Example: Allow established connections from WAN while blocking new incoming connections
        :param pulumi.Input[_builtins.bool] state_invalid: Match where the state is invalid.
        :param pulumi.Input[_builtins.bool] state_new: Match where the state is new.
        :param pulumi.Input[_builtins.bool] state_related: Match where the state is related.
        """
        if action is not None:
            pulumi.set(__self__, "action", action)
        if dst_address is not None:
            pulumi.set(__self__, "dst_address", dst_address)
        if dst_address_ipv6 is not None:
            pulumi.set(__self__, "dst_address_ipv6", dst_address_ipv6)
        if dst_firewall_group_ids is not None:
            pulumi.set(__self__, "dst_firewall_group_ids", dst_firewall_group_ids)
        if dst_network_id is not None:
            pulumi.set(__self__, "dst_network_id", dst_network_id)
        if dst_network_type is not None:
            pulumi.set(__self__, "dst_network_type", dst_network_type)
        if dst_port is not None:
            pulumi.set(__self__, "dst_port", dst_port)
        if enabled is not None:
            pulumi.set(__self__, "enabled", enabled)
        if icmp_typename is not None:
            pulumi.set(__self__, "icmp_typename", icmp_typename)
        if icmp_v6_typename is not None:
            pulumi.set(__self__, "icmp_v6_typename", icmp_v6_typename)
        if ip_sec is not None:
            pulumi.set(__self__, "ip_sec", ip_sec)
        if logging is not None:
            pulumi.set(__self__, "logging", logging)
        if name is not None:
            pulumi.set(__self__, "name", name)
        if protocol is not None:
            pulumi.set(__self__, "protocol", protocol)
        if protocol_v6 is not None:
            pulumi.set(__self__, "protocol_v6", protocol_v6)
        if rule_index is not None:
            pulumi.set(__self__, "rule_index", rule_index)
        if ruleset is not None:
            pulumi.set(__self__, "ruleset", ruleset)
        if site is not None:
            pulumi.set(__self__, "site", site)
        if src_address is not None:
            pulumi.set(__self__, "src_address", src_address)
        if src_address_ipv6 is not None:
            pulumi.set(__self__, "src_address_ipv6", src_address_ipv6)
        if src_firewall_group_ids is not None:
            pulumi.set(__self__, "src_firewall_group_ids", src_firewall_group_ids)
        if src_mac is not None:
            pulumi.set(__self__, "src_mac", src_mac)
        if src_network_id is not None:
            pulumi.set(__self__, "src_network_id", src_network_id)
        if src_network_type is not None:
            pulumi.set(__self__, "src_network_type", src_network_type)
        if src_port is not None:
            pulumi.set(__self__, "src_port", src_port)
        if state_established is not None:
            pulumi.set(__self__, "state_established", state_established)
        if state_invalid is not None:
            pulumi.set(__self__, "state_invalid", state_invalid)
        if state_new is not None:
            pulumi.set(__self__, "state_new", state_new)
        if state_related is not None:
            pulumi.set(__self__, "state_related", state_related)

    @_builtins.property
    @pulumi.getter
    def action(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The action to take when traffic matches this rule. Valid values are:
          * `accept` - Allow the traffic
          * `drop` - Silently block the traffic
          * `reject` - Block the traffic and send an ICMP rejection message
        """
        return pulumi.get(self, "action")

    @action.setter
    def action(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "action", value)

    @_builtins.property
    @pulumi.getter(name="dstAddress")
    def dst_address(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The destination IPv4 address or network in CIDR notation (e.g., '192.168.1.10' or '192.168.0.0/24'). The format must match dst_network_type - use a single IP for ADDRv4 or CIDR for NETv4.
        """
        return pulumi.get(self, "dst_address")

    @dst_address.setter
    def dst_address(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "dst_address", value)

    @_builtins.property
    @pulumi.getter(name="dstAddressIpv6")
    def dst_address_ipv6(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The destination IPv6 address or network in CIDR notation (e.g., '2001:db8::1' or '2001:db8::/64'). Used for IPv6 firewall rules.
        """
        return pulumi.get(self, "dst_address_ipv6")

    @dst_address_ipv6.setter
    def dst_address_ipv6(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "dst_address_ipv6", value)

    @_builtins.property
    @pulumi.getter(name="dstFirewallGroupIds")
    def dst_firewall_group_ids(self) -> Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]]:
        """
        A list of firewall group IDs to use as destinations. Groups can contain IP addresses, networks, or port numbers. This allows you to create reusable sets of addresses/ports and reference them in multiple rules.
        """
        return pulumi.get(self, "dst_firewall_group_ids")

    @dst_firewall_group_ids.setter
    def dst_firewall_group_ids(self, value: Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]]):
        pulumi.set(self, "dst_firewall_group_ids", value)

    @_builtins.property
    @pulumi.getter(name="dstNetworkId")
    def dst_network_id(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The ID of the destination network this rule applies to. This can be found in the URL when viewing the network in the UniFi controller.
        """
        return pulumi.get(self, "dst_network_id")

    @dst_network_id.setter
    def dst_network_id(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "dst_network_id", value)

    @_builtins.property
    @pulumi.getter(name="dstNetworkType")
    def dst_network_type(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The type of destination network address. Valid values are:
          * `ADDRv4` - Single IPv4 address
          * `NETv4` - IPv4 network in CIDR notation
        """
        return pulumi.get(self, "dst_network_type")

    @dst_network_type.setter
    def dst_network_type(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "dst_network_type", value)

    @_builtins.property
    @pulumi.getter(name="dstPort")
    def dst_port(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The destination port(s) for this rule. Can be:
          * A single port number (e.g., '80')
          * A port range (e.g., '8000:8080')
          * A list of ports/ranges separated by commas
        """
        return pulumi.get(self, "dst_port")

    @dst_port.setter
    def dst_port(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "dst_port", value)

    @_builtins.property
    @pulumi.getter
    def enabled(self) -> Optional[pulumi.Input[_builtins.bool]]:
        """
        Whether this firewall rule is active (true) or disabled (false). Defaults to true.
        """
        return pulumi.get(self, "enabled")

    @enabled.setter
    def enabled(self, value: Optional[pulumi.Input[_builtins.bool]]):
        pulumi.set(self, "enabled", value)

    @_builtins.property
    @pulumi.getter(name="icmpTypename")
    def icmp_typename(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The ICMP type name when protocol is set to 'icmp'. Common values include:
          * `echo-request` - ICMP ping requests
          * `echo-reply` - ICMP ping replies
          * `destination-unreachable` - Host/network unreachable messages
          * `time-exceeded` - TTL exceeded messages (traceroute)
        """
        return pulumi.get(self, "icmp_typename")

    @icmp_typename.setter
    def icmp_typename(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "icmp_typename", value)

    @_builtins.property
    @pulumi.getter(name="icmpV6Typename")
    def icmp_v6_typename(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The ICMPv6 type name when protocol_v6 is set to 'ipv6-icmp'. Common values (not all are listed) include:
          * `echo-request` - IPv6 ping requests
          * `echo-reply` - IPv6 ping replies
          * `neighbor-solicitation` - IPv6 neighbor discovery
          * `neighbor-advertisement` - IPv6 neighbor announcements
          * `destination-unreachable` - Host/network unreachable messages
          * `packet-too-big` - Path MTU discovery messages
        """
        return pulumi.get(self, "icmp_v6_typename")

    @icmp_v6_typename.setter
    def icmp_v6_typename(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "icmp_v6_typename", value)

    @_builtins.property
    @pulumi.getter(name="ipSec")
    def ip_sec(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        Specify whether the rule matches on IPsec packets. Can be one of `match-ipsec` or `match-none`.
        """
        return pulumi.get(self, "ip_sec")

    @ip_sec.setter
    def ip_sec(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "ip_sec", value)

    @_builtins.property
    @pulumi.getter
    def logging(self) -> Optional[pulumi.Input[_builtins.bool]]:
        """
        Enable logging for the firewall rule.
        """
        return pulumi.get(self, "logging")

    @logging.setter
    def logging(self, value: Optional[pulumi.Input[_builtins.bool]]):
        pulumi.set(self, "logging", value)

    @_builtins.property
    @pulumi.getter
    def name(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        A friendly name for the firewall rule. This helps identify the rule's purpose in the UniFi controller UI.
        """
        return pulumi.get(self, "name")

    @name.setter
    def name(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "name", value)

    @_builtins.property
    @pulumi.getter
    def protocol(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The IPv4 protocol this rule applies to. Common values (not all are listed) include:
          * `all` - Match all protocols
          * `tcp` - TCP traffic only (e.g., web, email)
          * `udp` - UDP traffic only (e.g., DNS, VoIP)
          * `tcp_udp` - Both TCP and UDP
          * `icmp` - ICMP traffic (ping, traceroute)
          * Protocol numbers (1-255) for other protocols

        Examples:
          * Use 'tcp' for web server rules (ports 80, 443)
          * Use 'udp' for VoIP or gaming traffic
          * Use 'all' for general network access rules
        """
        return pulumi.get(self, "protocol")

    @protocol.setter
    def protocol(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "protocol", value)

    @_builtins.property
    @pulumi.getter(name="protocolV6")
    def protocol_v6(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The IPv6 protocol this rule applies to. Similar to 'protocol' but for IPv6 traffic. Common values (not all are listed) include:
          * `all` - Match all protocols
          * `tcp` - TCP traffic only
          * `udp` - UDP traffic only
          * `tcp_udp` - Both TCP and UDP traffic
          * `ipv6-icmp` - ICMPv6 traffic
        """
        return pulumi.get(self, "protocol_v6")

    @protocol_v6.setter
    def protocol_v6(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "protocol_v6", value)

    @_builtins.property
    @pulumi.getter(name="ruleIndex")
    def rule_index(self) -> Optional[pulumi.Input[_builtins.int]]:
        """
        The processing order for this rule. Lower numbers are processed first. Custom rules should use:
          * 2000-2999 for rules processed before auto-generated rules
          * 4000-4999 for rules processed after auto-generated rules
        """
        return pulumi.get(self, "rule_index")

    @rule_index.setter
    def rule_index(self, value: Optional[pulumi.Input[_builtins.int]]):
        pulumi.set(self, "rule_index", value)

    @_builtins.property
    @pulumi.getter
    def ruleset(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        Defines which traffic flow this rule applies to. The format is [NETWORK]_[DIRECTION], where:
          * NETWORK can be: WAN, LAN, GUEST (or their IPv6 variants WANv6, LANv6, GUESTv6)
          * DIRECTION can be:
            * IN - Traffic entering the network
            * OUT - Traffic leaving the network
            * LOCAL - Traffic destined for the USG/UDM itself

        Examples: WAN_IN (incoming WAN traffic), LAN_OUT (outgoing LAN traffic), GUEST_LOCAL (traffic to Controller from guest network)
        """
        return pulumi.get(self, "ruleset")

    @ruleset.setter
    def ruleset(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "ruleset", value)

    @_builtins.property
    @pulumi.getter
    def site(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The name of the UniFi site where the firewall rule should be created. If not specified, the default site will be used.
        """
        return pulumi.get(self, "site")

    @site.setter
    def site(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "site", value)

    @_builtins.property
    @pulumi.getter(name="srcAddress")
    def src_address(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The source IPv4 address for the firewall rule.
        """
        return pulumi.get(self, "src_address")

    @src_address.setter
    def src_address(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "src_address", value)

    @_builtins.property
    @pulumi.getter(name="srcAddressIpv6")
    def src_address_ipv6(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The source IPv6 address or network in CIDR notation (e.g., '2001:db8::1' or '2001:db8::/64'). Used for IPv6 firewall rules.
        """
        return pulumi.get(self, "src_address_ipv6")

    @src_address_ipv6.setter
    def src_address_ipv6(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "src_address_ipv6", value)

    @_builtins.property
    @pulumi.getter(name="srcFirewallGroupIds")
    def src_firewall_group_ids(self) -> Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]]:
        """
        A list of firewall group IDs to use as sources. Groups can contain:
          * IP Address Groups - For matching specific IP addresses
          * Network Groups - For matching entire subnets
          * Port Groups - For matching specific port numbers

        Example uses:
          * Group of trusted admin IPs for remote access
          * Group of IoT device networks for isolation
          * Group of common service ports for allowing specific applications
        """
        return pulumi.get(self, "src_firewall_group_ids")

    @src_firewall_group_ids.setter
    def src_firewall_group_ids(self, value: Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]]):
        pulumi.set(self, "src_firewall_group_ids", value)

    @_builtins.property
    @pulumi.getter(name="srcMac")
    def src_mac(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The source MAC address this rule applies to. Use this to create rules that match specific devices regardless of their IP address. Format: 'XX:XX:XX:XX:XX:XX'. MAC addresses are case-insensitive.
        """
        return pulumi.get(self, "src_mac")

    @src_mac.setter
    def src_mac(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "src_mac", value)

    @_builtins.property
    @pulumi.getter(name="srcNetworkId")
    def src_network_id(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The ID of the source network this rule applies to. This can be found in the URL when viewing the network in the UniFi controller, or by using the network's name in the form `[site]/[network_name]`.
        """
        return pulumi.get(self, "src_network_id")

    @src_network_id.setter
    def src_network_id(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "src_network_id", value)

    @_builtins.property
    @pulumi.getter(name="srcNetworkType")
    def src_network_type(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The type of source network address. Valid values are:
          * `ADDRv4` - Single IPv4 address
          * `NETv4` - IPv4 network in CIDR notation
        """
        return pulumi.get(self, "src_network_type")

    @src_network_type.setter
    def src_network_type(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "src_network_type", value)

    @_builtins.property
    @pulumi.getter(name="srcPort")
    def src_port(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        The source port(s) for this rule. Can be:
          * A single port number (e.g., '80')
          * A port range (e.g., '8000:8080')
          * A list of ports/ranges separated by commas
        """
        return pulumi.get(self, "src_port")

    @src_port.setter
    def src_port(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "src_port", value)

    @_builtins.property
    @pulumi.getter(name="stateEstablished")
    def state_established(self) -> Optional[pulumi.Input[_builtins.bool]]:
        """
        Match established connections. When enabled:
          * Rule only applies to packets that are part of an existing connection
          * Useful for allowing return traffic without creating separate rules
          * Common in WAN_IN rules to allow responses to outbound connections

        Example: Allow established connections from WAN while blocking new incoming connections
        """
        return pulumi.get(self, "state_established")

    @state_established.setter
    def state_established(self, value: Optional[pulumi.Input[_builtins.bool]]):
        pulumi.set(self, "state_established", value)

    @_builtins.property
    @pulumi.getter(name="stateInvalid")
    def state_invalid(self) -> Optional[pulumi.Input[_builtins.bool]]:
        """
        Match where the state is invalid.
        """
        return pulumi.get(self, "state_invalid")

    @state_invalid.setter
    def state_invalid(self, value: Optional[pulumi.Input[_builtins.bool]]):
        pulumi.set(self, "state_invalid", value)

    @_builtins.property
    @pulumi.getter(name="stateNew")
    def state_new(self) -> Optional[pulumi.Input[_builtins.bool]]:
        """
        Match where the state is new.
        """
        return pulumi.get(self, "state_new")

    @state_new.setter
    def state_new(self, value: Optional[pulumi.Input[_builtins.bool]]):
        pulumi.set(self, "state_new", value)

    @_builtins.property
    @pulumi.getter(name="stateRelated")
    def state_related(self) -> Optional[pulumi.Input[_builtins.bool]]:
        """
        Match where the state is related.
        """
        return pulumi.get(self, "state_related")

    @state_related.setter
    def state_related(self, value: Optional[pulumi.Input[_builtins.bool]]):
        pulumi.set(self, "state_related", value)


@pulumi.type_token("unifi:firewall/rule:Rule")
class Rule(pulumi.CustomResource):
    @overload
    def __init__(__self__,
                 resource_name: str,
                 opts: Optional[pulumi.ResourceOptions] = None,
                 action: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_address: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_address_ipv6: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_firewall_group_ids: Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]] = None,
                 dst_network_id: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_network_type: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_port: Optional[pulumi.Input[_builtins.str]] = None,
                 enabled: Optional[pulumi.Input[_builtins.bool]] = None,
                 icmp_typename: Optional[pulumi.Input[_builtins.str]] = None,
                 icmp_v6_typename: Optional[pulumi.Input[_builtins.str]] = None,
                 ip_sec: Optional[pulumi.Input[_builtins.str]] = None,
                 logging: Optional[pulumi.Input[_builtins.bool]] = None,
                 name: Optional[pulumi.Input[_builtins.str]] = None,
                 protocol: Optional[pulumi.Input[_builtins.str]] = None,
                 protocol_v6: Optional[pulumi.Input[_builtins.str]] = None,
                 rule_index: Optional[pulumi.Input[_builtins.int]] = None,
                 ruleset: Optional[pulumi.Input[_builtins.str]] = None,
                 site: Optional[pulumi.Input[_builtins.str]] = None,
                 src_address: Optional[pulumi.Input[_builtins.str]] = None,
                 src_address_ipv6: Optional[pulumi.Input[_builtins.str]] = None,
                 src_firewall_group_ids: Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]] = None,
                 src_mac: Optional[pulumi.Input[_builtins.str]] = None,
                 src_network_id: Optional[pulumi.Input[_builtins.str]] = None,
                 src_network_type: Optional[pulumi.Input[_builtins.str]] = None,
                 src_port: Optional[pulumi.Input[_builtins.str]] = None,
                 state_established: Optional[pulumi.Input[_builtins.bool]] = None,
                 state_invalid: Optional[pulumi.Input[_builtins.bool]] = None,
                 state_new: Optional[pulumi.Input[_builtins.bool]] = None,
                 state_related: Optional[pulumi.Input[_builtins.bool]] = None,
                 __props__=None):
        """
        The `firewall.Rule` resource manages firewall rules.

        This resource allows you to create and manage firewall rules that control traffic flow between different network segments (WAN, LAN, Guest) for both IPv4 and IPv6 traffic. Rules can be configured to allow, drop, or reject traffic based on various criteria including protocols, ports, and IP addresses.

        Rules are processed in order based on their `rule_index`, with lower numbers being processed first. Custom rules should use indices between 2000-2999 or 4000-4999 to avoid conflicts with system rules.

        ## Example Usage

        ```python
        import pulumi
        import pulumiverse_unifi as unifi

        config = pulumi.Config()
        ip_address = config.require("ipAddress")
        drop_all = unifi.firewall.Rule("drop_all",
            name="drop all",
            action="drop",
            ruleset="LAN_IN",
            rule_index=2011,
            protocol="all",
            dst_address=ip_address)
        ```

        ## Import

        import using the ID from the controller API/UI

        ```sh
        $ pulumi import unifi:firewall/rule:Rule my_rule 5f7080eb6b8969064f80494f
        ```

        :param str resource_name: The name of the resource.
        :param pulumi.ResourceOptions opts: Options for the resource.
        :param pulumi.Input[_builtins.str] action: The action to take when traffic matches this rule. Valid values are:
                 * `accept` - Allow the traffic
                 * `drop` - Silently block the traffic
                 * `reject` - Block the traffic and send an ICMP rejection message
        :param pulumi.Input[_builtins.str] dst_address: The destination IPv4 address or network in CIDR notation (e.g., '192.168.1.10' or '192.168.0.0/24'). The format must match dst_network_type - use a single IP for ADDRv4 or CIDR for NETv4.
        :param pulumi.Input[_builtins.str] dst_address_ipv6: The destination IPv6 address or network in CIDR notation (e.g., '2001:db8::1' or '2001:db8::/64'). Used for IPv6 firewall rules.
        :param pulumi.Input[Sequence[pulumi.Input[_builtins.str]]] dst_firewall_group_ids: A list of firewall group IDs to use as destinations. Groups can contain IP addresses, networks, or port numbers. This allows you to create reusable sets of addresses/ports and reference them in multiple rules.
        :param pulumi.Input[_builtins.str] dst_network_id: The ID of the destination network this rule applies to. This can be found in the URL when viewing the network in the UniFi controller.
        :param pulumi.Input[_builtins.str] dst_network_type: The type of destination network address. Valid values are:
                 * `ADDRv4` - Single IPv4 address
                 * `NETv4` - IPv4 network in CIDR notation
        :param pulumi.Input[_builtins.str] dst_port: The destination port(s) for this rule. Can be:
                 * A single port number (e.g., '80')
                 * A port range (e.g., '8000:8080')
                 * A list of ports/ranges separated by commas
        :param pulumi.Input[_builtins.bool] enabled: Whether this firewall rule is active (true) or disabled (false). Defaults to true.
        :param pulumi.Input[_builtins.str] icmp_typename: The ICMP type name when protocol is set to 'icmp'. Common values include:
                 * `echo-request` - ICMP ping requests
                 * `echo-reply` - ICMP ping replies
                 * `destination-unreachable` - Host/network unreachable messages
                 * `time-exceeded` - TTL exceeded messages (traceroute)
        :param pulumi.Input[_builtins.str] icmp_v6_typename: The ICMPv6 type name when protocol_v6 is set to 'ipv6-icmp'. Common values (not all are listed) include:
                 * `echo-request` - IPv6 ping requests
                 * `echo-reply` - IPv6 ping replies
                 * `neighbor-solicitation` - IPv6 neighbor discovery
                 * `neighbor-advertisement` - IPv6 neighbor announcements
                 * `destination-unreachable` - Host/network unreachable messages
                 * `packet-too-big` - Path MTU discovery messages
        :param pulumi.Input[_builtins.str] ip_sec: Specify whether the rule matches on IPsec packets. Can be one of `match-ipsec` or `match-none`.
        :param pulumi.Input[_builtins.bool] logging: Enable logging for the firewall rule.
        :param pulumi.Input[_builtins.str] name: A friendly name for the firewall rule. This helps identify the rule's purpose in the UniFi controller UI.
        :param pulumi.Input[_builtins.str] protocol: The IPv4 protocol this rule applies to. Common values (not all are listed) include:
                 * `all` - Match all protocols
                 * `tcp` - TCP traffic only (e.g., web, email)
                 * `udp` - UDP traffic only (e.g., DNS, VoIP)
                 * `tcp_udp` - Both TCP and UDP
                 * `icmp` - ICMP traffic (ping, traceroute)
                 * Protocol numbers (1-255) for other protocols
               
               Examples:
                 * Use 'tcp' for web server rules (ports 80, 443)
                 * Use 'udp' for VoIP or gaming traffic
                 * Use 'all' for general network access rules
        :param pulumi.Input[_builtins.str] protocol_v6: The IPv6 protocol this rule applies to. Similar to 'protocol' but for IPv6 traffic. Common values (not all are listed) include:
                 * `all` - Match all protocols
                 * `tcp` - TCP traffic only
                 * `udp` - UDP traffic only
                 * `tcp_udp` - Both TCP and UDP traffic
                 * `ipv6-icmp` - ICMPv6 traffic
        :param pulumi.Input[_builtins.int] rule_index: The processing order for this rule. Lower numbers are processed first. Custom rules should use:
                 * 2000-2999 for rules processed before auto-generated rules
                 * 4000-4999 for rules processed after auto-generated rules
        :param pulumi.Input[_builtins.str] ruleset: Defines which traffic flow this rule applies to. The format is [NETWORK]_[DIRECTION], where:
                 * NETWORK can be: WAN, LAN, GUEST (or their IPv6 variants WANv6, LANv6, GUESTv6)
                 * DIRECTION can be:
                   * IN - Traffic entering the network
                   * OUT - Traffic leaving the network
                   * LOCAL - Traffic destined for the USG/UDM itself
               
               Examples: WAN_IN (incoming WAN traffic), LAN_OUT (outgoing LAN traffic), GUEST_LOCAL (traffic to Controller from guest network)
        :param pulumi.Input[_builtins.str] site: The name of the UniFi site where the firewall rule should be created. If not specified, the default site will be used.
        :param pulumi.Input[_builtins.str] src_address: The source IPv4 address for the firewall rule.
        :param pulumi.Input[_builtins.str] src_address_ipv6: The source IPv6 address or network in CIDR notation (e.g., '2001:db8::1' or '2001:db8::/64'). Used for IPv6 firewall rules.
        :param pulumi.Input[Sequence[pulumi.Input[_builtins.str]]] src_firewall_group_ids: A list of firewall group IDs to use as sources. Groups can contain:
                 * IP Address Groups - For matching specific IP addresses
                 * Network Groups - For matching entire subnets
                 * Port Groups - For matching specific port numbers
               
               Example uses:
                 * Group of trusted admin IPs for remote access
                 * Group of IoT device networks for isolation
                 * Group of common service ports for allowing specific applications
        :param pulumi.Input[_builtins.str] src_mac: The source MAC address this rule applies to. Use this to create rules that match specific devices regardless of their IP address. Format: 'XX:XX:XX:XX:XX:XX'. MAC addresses are case-insensitive.
        :param pulumi.Input[_builtins.str] src_network_id: The ID of the source network this rule applies to. This can be found in the URL when viewing the network in the UniFi controller, or by using the network's name in the form `[site]/[network_name]`.
        :param pulumi.Input[_builtins.str] src_network_type: The type of source network address. Valid values are:
                 * `ADDRv4` - Single IPv4 address
                 * `NETv4` - IPv4 network in CIDR notation
        :param pulumi.Input[_builtins.str] src_port: The source port(s) for this rule. Can be:
                 * A single port number (e.g., '80')
                 * A port range (e.g., '8000:8080')
                 * A list of ports/ranges separated by commas
        :param pulumi.Input[_builtins.bool] state_established: Match established connections. When enabled:
                 * Rule only applies to packets that are part of an existing connection
                 * Useful for allowing return traffic without creating separate rules
                 * Common in WAN_IN rules to allow responses to outbound connections
               
               Example: Allow established connections from WAN while blocking new incoming connections
        :param pulumi.Input[_builtins.bool] state_invalid: Match where the state is invalid.
        :param pulumi.Input[_builtins.bool] state_new: Match where the state is new.
        :param pulumi.Input[_builtins.bool] state_related: Match where the state is related.
        """
        ...
    @overload
    def __init__(__self__,
                 resource_name: str,
                 args: RuleArgs,
                 opts: Optional[pulumi.ResourceOptions] = None):
        """
        The `firewall.Rule` resource manages firewall rules.

        This resource allows you to create and manage firewall rules that control traffic flow between different network segments (WAN, LAN, Guest) for both IPv4 and IPv6 traffic. Rules can be configured to allow, drop, or reject traffic based on various criteria including protocols, ports, and IP addresses.

        Rules are processed in order based on their `rule_index`, with lower numbers being processed first. Custom rules should use indices between 2000-2999 or 4000-4999 to avoid conflicts with system rules.

        ## Example Usage

        ```python
        import pulumi
        import pulumiverse_unifi as unifi

        config = pulumi.Config()
        ip_address = config.require("ipAddress")
        drop_all = unifi.firewall.Rule("drop_all",
            name="drop all",
            action="drop",
            ruleset="LAN_IN",
            rule_index=2011,
            protocol="all",
            dst_address=ip_address)
        ```

        ## Import

        import using the ID from the controller API/UI

        ```sh
        $ pulumi import unifi:firewall/rule:Rule my_rule 5f7080eb6b8969064f80494f
        ```

        :param str resource_name: The name of the resource.
        :param RuleArgs args: The arguments to use to populate this resource's properties.
        :param pulumi.ResourceOptions opts: Options for the resource.
        """
        ...
    def __init__(__self__, resource_name: str, *args, **kwargs):
        resource_args, opts = _utilities.get_resource_args_opts(RuleArgs, pulumi.ResourceOptions, *args, **kwargs)
        if resource_args is not None:
            __self__._internal_init(resource_name, opts, **resource_args.__dict__)
        else:
            __self__._internal_init(resource_name, *args, **kwargs)

    def _internal_init(__self__,
                 resource_name: str,
                 opts: Optional[pulumi.ResourceOptions] = None,
                 action: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_address: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_address_ipv6: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_firewall_group_ids: Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]] = None,
                 dst_network_id: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_network_type: Optional[pulumi.Input[_builtins.str]] = None,
                 dst_port: Optional[pulumi.Input[_builtins.str]] = None,
                 enabled: Optional[pulumi.Input[_builtins.bool]] = None,
                 icmp_typename: Optional[pulumi.Input[_builtins.str]] = None,
                 icmp_v6_typename: Optional[pulumi.Input[_builtins.str]] = None,
                 ip_sec: Optional[pulumi.Input[_builtins.str]] = None,
                 logging: Optional[pulumi.Input[_builtins.bool]] = None,
                 name: Optional[pulumi.Input[_builtins.str]] = None,
                 protocol: Optional[pulumi.Input[_builtins.str]] = None,
                 protocol_v6: Optional[pulumi.Input[_builtins.str]] = None,
                 rule_index: Optional[pulumi.Input[_builtins.int]] = None,
                 ruleset: Optional[pulumi.Input[_builtins.str]] = None,
                 site: Optional[pulumi.Input[_builtins.str]] = None,
                 src_address: Optional[pulumi.Input[_builtins.str]] = None,
                 src_address_ipv6: Optional[pulumi.Input[_builtins.str]] = None,
                 src_firewall_group_ids: Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]] = None,
                 src_mac: Optional[pulumi.Input[_builtins.str]] = None,
                 src_network_id: Optional[pulumi.Input[_builtins.str]] = None,
                 src_network_type: Optional[pulumi.Input[_builtins.str]] = None,
                 src_port: Optional[pulumi.Input[_builtins.str]] = None,
                 state_established: Optional[pulumi.Input[_builtins.bool]] = None,
                 state_invalid: Optional[pulumi.Input[_builtins.bool]] = None,
                 state_new: Optional[pulumi.Input[_builtins.bool]] = None,
                 state_related: Optional[pulumi.Input[_builtins.bool]] = None,
                 __props__=None):
        opts = pulumi.ResourceOptions.merge(_utilities.get_resource_opts_defaults(), opts)
        if not isinstance(opts, pulumi.ResourceOptions):
            raise TypeError('Expected resource options to be a ResourceOptions instance')
        if opts.id is None:
            if __props__ is not None:
                raise TypeError('__props__ is only valid when passed in combination with a valid opts.id to get an existing resource')
            __props__ = RuleArgs.__new__(RuleArgs)

            if action is None and not opts.urn:
                raise TypeError("Missing required property 'action'")
            __props__.__dict__["action"] = action
            __props__.__dict__["dst_address"] = dst_address
            __props__.__dict__["dst_address_ipv6"] = dst_address_ipv6
            __props__.__dict__["dst_firewall_group_ids"] = dst_firewall_group_ids
            __props__.__dict__["dst_network_id"] = dst_network_id
            __props__.__dict__["dst_network_type"] = dst_network_type
            __props__.__dict__["dst_port"] = dst_port
            __props__.__dict__["enabled"] = enabled
            __props__.__dict__["icmp_typename"] = icmp_typename
            __props__.__dict__["icmp_v6_typename"] = icmp_v6_typename
            __props__.__dict__["ip_sec"] = ip_sec
            __props__.__dict__["logging"] = logging
            __props__.__dict__["name"] = name
            __props__.__dict__["protocol"] = protocol
            __props__.__dict__["protocol_v6"] = protocol_v6
            if rule_index is None and not opts.urn:
                raise TypeError("Missing required property 'rule_index'")
            __props__.__dict__["rule_index"] = rule_index
            if ruleset is None and not opts.urn:
                raise TypeError("Missing required property 'ruleset'")
            __props__.__dict__["ruleset"] = ruleset
            __props__.__dict__["site"] = site
            __props__.__dict__["src_address"] = src_address
            __props__.__dict__["src_address_ipv6"] = src_address_ipv6
            __props__.__dict__["src_firewall_group_ids"] = src_firewall_group_ids
            __props__.__dict__["src_mac"] = src_mac
            __props__.__dict__["src_network_id"] = src_network_id
            __props__.__dict__["src_network_type"] = src_network_type
            __props__.__dict__["src_port"] = src_port
            __props__.__dict__["state_established"] = state_established
            __props__.__dict__["state_invalid"] = state_invalid
            __props__.__dict__["state_new"] = state_new
            __props__.__dict__["state_related"] = state_related
        super(Rule, __self__).__init__(
            'unifi:firewall/rule:Rule',
            resource_name,
            __props__,
            opts)

    @staticmethod
    def get(resource_name: str,
            id: pulumi.Input[str],
            opts: Optional[pulumi.ResourceOptions] = None,
            action: Optional[pulumi.Input[_builtins.str]] = None,
            dst_address: Optional[pulumi.Input[_builtins.str]] = None,
            dst_address_ipv6: Optional[pulumi.Input[_builtins.str]] = None,
            dst_firewall_group_ids: Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]] = None,
            dst_network_id: Optional[pulumi.Input[_builtins.str]] = None,
            dst_network_type: Optional[pulumi.Input[_builtins.str]] = None,
            dst_port: Optional[pulumi.Input[_builtins.str]] = None,
            enabled: Optional[pulumi.Input[_builtins.bool]] = None,
            icmp_typename: Optional[pulumi.Input[_builtins.str]] = None,
            icmp_v6_typename: Optional[pulumi.Input[_builtins.str]] = None,
            ip_sec: Optional[pulumi.Input[_builtins.str]] = None,
            logging: Optional[pulumi.Input[_builtins.bool]] = None,
            name: Optional[pulumi.Input[_builtins.str]] = None,
            protocol: Optional[pulumi.Input[_builtins.str]] = None,
            protocol_v6: Optional[pulumi.Input[_builtins.str]] = None,
            rule_index: Optional[pulumi.Input[_builtins.int]] = None,
            ruleset: Optional[pulumi.Input[_builtins.str]] = None,
            site: Optional[pulumi.Input[_builtins.str]] = None,
            src_address: Optional[pulumi.Input[_builtins.str]] = None,
            src_address_ipv6: Optional[pulumi.Input[_builtins.str]] = None,
            src_firewall_group_ids: Optional[pulumi.Input[Sequence[pulumi.Input[_builtins.str]]]] = None,
            src_mac: Optional[pulumi.Input[_builtins.str]] = None,
            src_network_id: Optional[pulumi.Input[_builtins.str]] = None,
            src_network_type: Optional[pulumi.Input[_builtins.str]] = None,
            src_port: Optional[pulumi.Input[_builtins.str]] = None,
            state_established: Optional[pulumi.Input[_builtins.bool]] = None,
            state_invalid: Optional[pulumi.Input[_builtins.bool]] = None,
            state_new: Optional[pulumi.Input[_builtins.bool]] = None,
            state_related: Optional[pulumi.Input[_builtins.bool]] = None) -> 'Rule':
        """
        Get an existing Rule resource's state with the given name, id, and optional extra
        properties used to qualify the lookup.

        :param str resource_name: The unique name of the resulting resource.
        :param pulumi.Input[str] id: The unique provider ID of the resource to lookup.
        :param pulumi.ResourceOptions opts: Options for the resource.
        :param pulumi.Input[_builtins.str] action: The action to take when traffic matches this rule. Valid values are:
                 * `accept` - Allow the traffic
                 * `drop` - Silently block the traffic
                 * `reject` - Block the traffic and send an ICMP rejection message
        :param pulumi.Input[_builtins.str] dst_address: The destination IPv4 address or network in CIDR notation (e.g., '192.168.1.10' or '192.168.0.0/24'). The format must match dst_network_type - use a single IP for ADDRv4 or CIDR for NETv4.
        :param pulumi.Input[_builtins.str] dst_address_ipv6: The destination IPv6 address or network in CIDR notation (e.g., '2001:db8::1' or '2001:db8::/64'). Used for IPv6 firewall rules.
        :param pulumi.Input[Sequence[pulumi.Input[_builtins.str]]] dst_firewall_group_ids: A list of firewall group IDs to use as destinations. Groups can contain IP addresses, networks, or port numbers. This allows you to create reusable sets of addresses/ports and reference them in multiple rules.
        :param pulumi.Input[_builtins.str] dst_network_id: The ID of the destination network this rule applies to. This can be found in the URL when viewing the network in the UniFi controller.
        :param pulumi.Input[_builtins.str] dst_network_type: The type of destination network address. Valid values are:
                 * `ADDRv4` - Single IPv4 address
                 * `NETv4` - IPv4 network in CIDR notation
        :param pulumi.Input[_builtins.str] dst_port: The destination port(s) for this rule. Can be:
                 * A single port number (e.g., '80')
                 * A port range (e.g., '8000:8080')
                 * A list of ports/ranges separated by commas
        :param pulumi.Input[_builtins.bool] enabled: Whether this firewall rule is active (true) or disabled (false). Defaults to true.
        :param pulumi.Input[_builtins.str] icmp_typename: The ICMP type name when protocol is set to 'icmp'. Common values include:
                 * `echo-request` - ICMP ping requests
                 * `echo-reply` - ICMP ping replies
                 * `destination-unreachable` - Host/network unreachable messages
                 * `time-exceeded` - TTL exceeded messages (traceroute)
        :param pulumi.Input[_builtins.str] icmp_v6_typename: The ICMPv6 type name when protocol_v6 is set to 'ipv6-icmp'. Common values (not all are listed) include:
                 * `echo-request` - IPv6 ping requests
                 * `echo-reply` - IPv6 ping replies
                 * `neighbor-solicitation` - IPv6 neighbor discovery
                 * `neighbor-advertisement` - IPv6 neighbor announcements
                 * `destination-unreachable` - Host/network unreachable messages
                 * `packet-too-big` - Path MTU discovery messages
        :param pulumi.Input[_builtins.str] ip_sec: Specify whether the rule matches on IPsec packets. Can be one of `match-ipsec` or `match-none`.
        :param pulumi.Input[_builtins.bool] logging: Enable logging for the firewall rule.
        :param pulumi.Input[_builtins.str] name: A friendly name for the firewall rule. This helps identify the rule's purpose in the UniFi controller UI.
        :param pulumi.Input[_builtins.str] protocol: The IPv4 protocol this rule applies to. Common values (not all are listed) include:
                 * `all` - Match all protocols
                 * `tcp` - TCP traffic only (e.g., web, email)
                 * `udp` - UDP traffic only (e.g., DNS, VoIP)
                 * `tcp_udp` - Both TCP and UDP
                 * `icmp` - ICMP traffic (ping, traceroute)
                 * Protocol numbers (1-255) for other protocols
               
               Examples:
                 * Use 'tcp' for web server rules (ports 80, 443)
                 * Use 'udp' for VoIP or gaming traffic
                 * Use 'all' for general network access rules
        :param pulumi.Input[_builtins.str] protocol_v6: The IPv6 protocol this rule applies to. Similar to 'protocol' but for IPv6 traffic. Common values (not all are listed) include:
                 * `all` - Match all protocols
                 * `tcp` - TCP traffic only
                 * `udp` - UDP traffic only
                 * `tcp_udp` - Both TCP and UDP traffic
                 * `ipv6-icmp` - ICMPv6 traffic
        :param pulumi.Input[_builtins.int] rule_index: The processing order for this rule. Lower numbers are processed first. Custom rules should use:
                 * 2000-2999 for rules processed before auto-generated rules
                 * 4000-4999 for rules processed after auto-generated rules
        :param pulumi.Input[_builtins.str] ruleset: Defines which traffic flow this rule applies to. The format is [NETWORK]_[DIRECTION], where:
                 * NETWORK can be: WAN, LAN, GUEST (or their IPv6 variants WANv6, LANv6, GUESTv6)
                 * DIRECTION can be:
                   * IN - Traffic entering the network
                   * OUT - Traffic leaving the network
                   * LOCAL - Traffic destined for the USG/UDM itself
               
               Examples: WAN_IN (incoming WAN traffic), LAN_OUT (outgoing LAN traffic), GUEST_LOCAL (traffic to Controller from guest network)
        :param pulumi.Input[_builtins.str] site: The name of the UniFi site where the firewall rule should be created. If not specified, the default site will be used.
        :param pulumi.Input[_builtins.str] src_address: The source IPv4 address for the firewall rule.
        :param pulumi.Input[_builtins.str] src_address_ipv6: The source IPv6 address or network in CIDR notation (e.g., '2001:db8::1' or '2001:db8::/64'). Used for IPv6 firewall rules.
        :param pulumi.Input[Sequence[pulumi.Input[_builtins.str]]] src_firewall_group_ids: A list of firewall group IDs to use as sources. Groups can contain:
                 * IP Address Groups - For matching specific IP addresses
                 * Network Groups - For matching entire subnets
                 * Port Groups - For matching specific port numbers
               
               Example uses:
                 * Group of trusted admin IPs for remote access
                 * Group of IoT device networks for isolation
                 * Group of common service ports for allowing specific applications
        :param pulumi.Input[_builtins.str] src_mac: The source MAC address this rule applies to. Use this to create rules that match specific devices regardless of their IP address. Format: 'XX:XX:XX:XX:XX:XX'. MAC addresses are case-insensitive.
        :param pulumi.Input[_builtins.str] src_network_id: The ID of the source network this rule applies to. This can be found in the URL when viewing the network in the UniFi controller, or by using the network's name in the form `[site]/[network_name]`.
        :param pulumi.Input[_builtins.str] src_network_type: The type of source network address. Valid values are:
                 * `ADDRv4` - Single IPv4 address
                 * `NETv4` - IPv4 network in CIDR notation
        :param pulumi.Input[_builtins.str] src_port: The source port(s) for this rule. Can be:
                 * A single port number (e.g., '80')
                 * A port range (e.g., '8000:8080')
                 * A list of ports/ranges separated by commas
        :param pulumi.Input[_builtins.bool] state_established: Match established connections. When enabled:
                 * Rule only applies to packets that are part of an existing connection
                 * Useful for allowing return traffic without creating separate rules
                 * Common in WAN_IN rules to allow responses to outbound connections
               
               Example: Allow established connections from WAN while blocking new incoming connections
        :param pulumi.Input[_builtins.bool] state_invalid: Match where the state is invalid.
        :param pulumi.Input[_builtins.bool] state_new: Match where the state is new.
        :param pulumi.Input[_builtins.bool] state_related: Match where the state is related.
        """
        opts = pulumi.ResourceOptions.merge(opts, pulumi.ResourceOptions(id=id))

        __props__ = _RuleState.__new__(_RuleState)

        __props__.__dict__["action"] = action
        __props__.__dict__["dst_address"] = dst_address
        __props__.__dict__["dst_address_ipv6"] = dst_address_ipv6
        __props__.__dict__["dst_firewall_group_ids"] = dst_firewall_group_ids
        __props__.__dict__["dst_network_id"] = dst_network_id
        __props__.__dict__["dst_network_type"] = dst_network_type
        __props__.__dict__["dst_port"] = dst_port
        __props__.__dict__["enabled"] = enabled
        __props__.__dict__["icmp_typename"] = icmp_typename
        __props__.__dict__["icmp_v6_typename"] = icmp_v6_typename
        __props__.__dict__["ip_sec"] = ip_sec
        __props__.__dict__["logging"] = logging
        __props__.__dict__["name"] = name
        __props__.__dict__["protocol"] = protocol
        __props__.__dict__["protocol_v6"] = protocol_v6
        __props__.__dict__["rule_index"] = rule_index
        __props__.__dict__["ruleset"] = ruleset
        __props__.__dict__["site"] = site
        __props__.__dict__["src_address"] = src_address
        __props__.__dict__["src_address_ipv6"] = src_address_ipv6
        __props__.__dict__["src_firewall_group_ids"] = src_firewall_group_ids
        __props__.__dict__["src_mac"] = src_mac
        __props__.__dict__["src_network_id"] = src_network_id
        __props__.__dict__["src_network_type"] = src_network_type
        __props__.__dict__["src_port"] = src_port
        __props__.__dict__["state_established"] = state_established
        __props__.__dict__["state_invalid"] = state_invalid
        __props__.__dict__["state_new"] = state_new
        __props__.__dict__["state_related"] = state_related
        return Rule(resource_name, opts=opts, __props__=__props__)

    @_builtins.property
    @pulumi.getter
    def action(self) -> pulumi.Output[_builtins.str]:
        """
        The action to take when traffic matches this rule. Valid values are:
          * `accept` - Allow the traffic
          * `drop` - Silently block the traffic
          * `reject` - Block the traffic and send an ICMP rejection message
        """
        return pulumi.get(self, "action")

    @_builtins.property
    @pulumi.getter(name="dstAddress")
    def dst_address(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        The destination IPv4 address or network in CIDR notation (e.g., '192.168.1.10' or '192.168.0.0/24'). The format must match dst_network_type - use a single IP for ADDRv4 or CIDR for NETv4.
        """
        return pulumi.get(self, "dst_address")

    @_builtins.property
    @pulumi.getter(name="dstAddressIpv6")
    def dst_address_ipv6(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        The destination IPv6 address or network in CIDR notation (e.g., '2001:db8::1' or '2001:db8::/64'). Used for IPv6 firewall rules.
        """
        return pulumi.get(self, "dst_address_ipv6")

    @_builtins.property
    @pulumi.getter(name="dstFirewallGroupIds")
    def dst_firewall_group_ids(self) -> pulumi.Output[Optional[Sequence[_builtins.str]]]:
        """
        A list of firewall group IDs to use as destinations. Groups can contain IP addresses, networks, or port numbers. This allows you to create reusable sets of addresses/ports and reference them in multiple rules.
        """
        return pulumi.get(self, "dst_firewall_group_ids")

    @_builtins.property
    @pulumi.getter(name="dstNetworkId")
    def dst_network_id(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        The ID of the destination network this rule applies to. This can be found in the URL when viewing the network in the UniFi controller.
        """
        return pulumi.get(self, "dst_network_id")

    @_builtins.property
    @pulumi.getter(name="dstNetworkType")
    def dst_network_type(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        The type of destination network address. Valid values are:
          * `ADDRv4` - Single IPv4 address
          * `NETv4` - IPv4 network in CIDR notation
        """
        return pulumi.get(self, "dst_network_type")

    @_builtins.property
    @pulumi.getter(name="dstPort")
    def dst_port(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        The destination port(s) for this rule. Can be:
          * A single port number (e.g., '80')
          * A port range (e.g., '8000:8080')
          * A list of ports/ranges separated by commas
        """
        return pulumi.get(self, "dst_port")

    @_builtins.property
    @pulumi.getter
    def enabled(self) -> pulumi.Output[Optional[_builtins.bool]]:
        """
        Whether this firewall rule is active (true) or disabled (false). Defaults to true.
        """
        return pulumi.get(self, "enabled")

    @_builtins.property
    @pulumi.getter(name="icmpTypename")
    def icmp_typename(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        The ICMP type name when protocol is set to 'icmp'. Common values include:
          * `echo-request` - ICMP ping requests
          * `echo-reply` - ICMP ping replies
          * `destination-unreachable` - Host/network unreachable messages
          * `time-exceeded` - TTL exceeded messages (traceroute)
        """
        return pulumi.get(self, "icmp_typename")

    @_builtins.property
    @pulumi.getter(name="icmpV6Typename")
    def icmp_v6_typename(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        The ICMPv6 type name when protocol_v6 is set to 'ipv6-icmp'. Common values (not all are listed) include:
          * `echo-request` - IPv6 ping requests
          * `echo-reply` - IPv6 ping replies
          * `neighbor-solicitation` - IPv6 neighbor discovery
          * `neighbor-advertisement` - IPv6 neighbor announcements
          * `destination-unreachable` - Host/network unreachable messages
          * `packet-too-big` - Path MTU discovery messages
        """
        return pulumi.get(self, "icmp_v6_typename")

    @_builtins.property
    @pulumi.getter(name="ipSec")
    def ip_sec(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        Specify whether the rule matches on IPsec packets. Can be one of `match-ipsec` or `match-none`.
        """
        return pulumi.get(self, "ip_sec")

    @_builtins.property
    @pulumi.getter
    def logging(self) -> pulumi.Output[Optional[_builtins.bool]]:
        """
        Enable logging for the firewall rule.
        """
        return pulumi.get(self, "logging")

    @_builtins.property
    @pulumi.getter
    def name(self) -> pulumi.Output[_builtins.str]:
        """
        A friendly name for the firewall rule. This helps identify the rule's purpose in the UniFi controller UI.
        """
        return pulumi.get(self, "name")

    @_builtins.property
    @pulumi.getter
    def protocol(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        The IPv4 protocol this rule applies to. Common values (not all are listed) include:
          * `all` - Match all protocols
          * `tcp` - TCP traffic only (e.g., web, email)
          * `udp` - UDP traffic only (e.g., DNS, VoIP)
          * `tcp_udp` - Both TCP and UDP
          * `icmp` - ICMP traffic (ping, traceroute)
          * Protocol numbers (1-255) for other protocols

        Examples:
          * Use 'tcp' for web server rules (ports 80, 443)
          * Use 'udp' for VoIP or gaming traffic
          * Use 'all' for general network access rules
        """
        return pulumi.get(self, "protocol")

    @_builtins.property
    @pulumi.getter(name="protocolV6")
    def protocol_v6(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        The IPv6 protocol this rule applies to. Similar to 'protocol' but for IPv6 traffic. Common values (not all are listed) include:
          * `all` - Match all protocols
          * `tcp` - TCP traffic only
          * `udp` - UDP traffic only
          * `tcp_udp` - Both TCP and UDP traffic
          * `ipv6-icmp` - ICMPv6 traffic
        """
        return pulumi.get(self, "protocol_v6")

    @_builtins.property
    @pulumi.getter(name="ruleIndex")
    def rule_index(self) -> pulumi.Output[_builtins.int]:
        """
        The processing order for this rule. Lower numbers are processed first. Custom rules should use:
          * 2000-2999 for rules processed before auto-generated rules
          * 4000-4999 for rules processed after auto-generated rules
        """
        return pulumi.get(self, "rule_index")

    @_builtins.property
    @pulumi.getter
    def ruleset(self) -> pulumi.Output[_builtins.str]:
        """
        Defines which traffic flow this rule applies to. The format is [NETWORK]_[DIRECTION], where:
          * NETWORK can be: WAN, LAN, GUEST (or their IPv6 variants WANv6, LANv6, GUESTv6)
          * DIRECTION can be:
            * IN - Traffic entering the network
            * OUT - Traffic leaving the network
            * LOCAL - Traffic destined for the USG/UDM itself

        Examples: WAN_IN (incoming WAN traffic), LAN_OUT (outgoing LAN traffic), GUEST_LOCAL (traffic to Controller from guest network)
        """
        return pulumi.get(self, "ruleset")

    @_builtins.property
    @pulumi.getter
    def site(self) -> pulumi.Output[_builtins.str]:
        """
        The name of the UniFi site where the firewall rule should be created. If not specified, the default site will be used.
        """
        return pulumi.get(self, "site")

    @_builtins.property
    @pulumi.getter(name="srcAddress")
    def src_address(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        The source IPv4 address for the firewall rule.
        """
        return pulumi.get(self, "src_address")

    @_builtins.property
    @pulumi.getter(name="srcAddressIpv6")
    def src_address_ipv6(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        The source IPv6 address or network in CIDR notation (e.g., '2001:db8::1' or '2001:db8::/64'). Used for IPv6 firewall rules.
        """
        return pulumi.get(self, "src_address_ipv6")

    @_builtins.property
    @pulumi.getter(name="srcFirewallGroupIds")
    def src_firewall_group_ids(self) -> pulumi.Output[Optional[Sequence[_builtins.str]]]:
        """
        A list of firewall group IDs to use as sources. Groups can contain:
          * IP Address Groups - For matching specific IP addresses
          * Network Groups - For matching entire subnets
          * Port Groups - For matching specific port numbers

        Example uses:
          * Group of trusted admin IPs for remote access
          * Group of IoT device networks for isolation
          * Group of common service ports for allowing specific applications
        """
        return pulumi.get(self, "src_firewall_group_ids")

    @_builtins.property
    @pulumi.getter(name="srcMac")
    def src_mac(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        The source MAC address this rule applies to. Use this to create rules that match specific devices regardless of their IP address. Format: 'XX:XX:XX:XX:XX:XX'. MAC addresses are case-insensitive.
        """
        return pulumi.get(self, "src_mac")

    @_builtins.property
    @pulumi.getter(name="srcNetworkId")
    def src_network_id(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        The ID of the source network this rule applies to. This can be found in the URL when viewing the network in the UniFi controller, or by using the network's name in the form `[site]/[network_name]`.
        """
        return pulumi.get(self, "src_network_id")

    @_builtins.property
    @pulumi.getter(name="srcNetworkType")
    def src_network_type(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        The type of source network address. Valid values are:
          * `ADDRv4` - Single IPv4 address
          * `NETv4` - IPv4 network in CIDR notation
        """
        return pulumi.get(self, "src_network_type")

    @_builtins.property
    @pulumi.getter(name="srcPort")
    def src_port(self) -> pulumi.Output[Optional[_builtins.str]]:
        """
        The source port(s) for this rule. Can be:
          * A single port number (e.g., '80')
          * A port range (e.g., '8000:8080')
          * A list of ports/ranges separated by commas
        """
        return pulumi.get(self, "src_port")

    @_builtins.property
    @pulumi.getter(name="stateEstablished")
    def state_established(self) -> pulumi.Output[Optional[_builtins.bool]]:
        """
        Match established connections. When enabled:
          * Rule only applies to packets that are part of an existing connection
          * Useful for allowing return traffic without creating separate rules
          * Common in WAN_IN rules to allow responses to outbound connections

        Example: Allow established connections from WAN while blocking new incoming connections
        """
        return pulumi.get(self, "state_established")

    @_builtins.property
    @pulumi.getter(name="stateInvalid")
    def state_invalid(self) -> pulumi.Output[Optional[_builtins.bool]]:
        """
        Match where the state is invalid.
        """
        return pulumi.get(self, "state_invalid")

    @_builtins.property
    @pulumi.getter(name="stateNew")
    def state_new(self) -> pulumi.Output[Optional[_builtins.bool]]:
        """
        Match where the state is new.
        """
        return pulumi.get(self, "state_new")

    @_builtins.property
    @pulumi.getter(name="stateRelated")
    def state_related(self) -> pulumi.Output[Optional[_builtins.bool]]:
        """
        Match where the state is related.
        """
        return pulumi.get(self, "state_related")

