Skip to content

FirewallPolicy

Package: @alchemy-unifi/network@0.1.2-nightly.20261027100339.gc70dd7b.0 · Source: FirewallPolicy.ts

A zone-based firewall policy: an action (ALLOW, BLOCK or REJECT) for traffic from a source zone to a destination zone, optionally narrowed by traffic filters, protocol, connection state, IPsec and a schedule.

Existing policies you made are adopted with --adopt by name and zone pair. Policies UniFi creates (system policies, and ones derived from UI objects) are never listed, adopted, changed or ordered.

Block a zone from Internal

import * as UnifiNetwork from "@alchemy-unifi/network";
import * as Alchemy from "alchemy";
import * as Effect from "effect/Effect";
export default Alchemy.Stack(
"HomeNetwork",
{ providers: UnifiNetwork.providers(), state: UnifiNetwork.state() },
Effect.gen(function* () {
const iot = yield* UnifiNetwork.FirewallZone("iot-zone", { name: "IoT" });
yield* UnifiNetwork.FirewallPolicy("block-iot-to-internal", {
name: "Block IoT to Internal",
enabled: true,
action: { type: "BLOCK" },
source: { zone: iot },
destination: { zone: UnifiNetwork.FirewallZone.INTERNAL },
ipProtocolScope: { ipVersion: "IPV4_AND_IPV6" },
loggingEnabled: false,
});
}),
);

source and destination each take a trafficFilter: networks, IP addresses (inline or a TrafficMatchingList), ports, MAC addresses and more. ipProtocolScope narrows the protocol.

Let guests print, on the printers’ IPP port only

import * as UnifiNetwork from "@alchemy-unifi/network";
import * as Effect from "effect/Effect";
export const allowPrinting = Effect.gen(function* () {
const { HOTSPOT, INTERNAL } = UnifiNetwork.FirewallZone;
const guests = yield* UnifiNetwork.Network.lookup({ name: "Guests" });
const printers = yield* UnifiNetwork.TrafficMatchingList.lookup({ name: "Printers" });
yield* UnifiNetwork.FirewallPolicy("guests-print", {
name: "Allow guests to print",
enabled: true,
action: { type: "ALLOW", allowReturnTraffic: true },
source: {
zone: HOTSPOT,
trafficFilter: { type: "NETWORK", networkFilter: { matchOpposite: false, networks: [guests] } },
},
destination: {
zone: INTERNAL,
trafficFilter: {
type: "IP_ADDRESS",
ipAddressFilter: { type: "TRAFFIC_MATCHING_LIST", matchOpposite: false, trafficMatchingList: printers },
portFilter: { type: "PORTS", matchOpposite: false, items: [{ type: "PORT_NUMBER", value: 631 }] },
},
},
ipProtocolScope: {
ipVersion: "IPV4_AND_IPV6",
protocolFilter: { type: "PRESET", preset: { name: "TCP_UDP" } },
},
loggingEnabled: false,
});
});

Some IDs are still raw: VPN servers, site-to-site tunnels and DPI applications in filters.

Changing source or destination updates the policy in place, and moves it to the end of the new zone pair. List it in that pair’s FirewallPolicyOrdering.

FirewallPolicy.lookup({ name, source?, destination? }) finds a policy the stack uses but doesn’t manage. Give the zones when the name isn’t unique.