Network policy reference

Use this page while editing profiles or rules. It covers the kernel's packet layers and netd's interface layer. Start with the safe profile workflow or firewall workflow if you are making a change rather than looking up syntax.

To findGo to
Addresses, gateway, DNS, hostname or MTUProfiles
Where a setting belongsRegistry layout
A match value or comparisonConditions
Allow, drop, reject, join or observeActions
Which layer can see a factLayers
Default image rulesDevelopment baseline
A policy pattern to adaptWorked examples

Writes take effect live and can interrupt remote access. Record the old values before editing. Check net status for accepted interface settings; for packet-policy changes, an administrator runs net policy wait and net policy. These are separate acceptance checks.

Profiles #

Profiles\<path> is how an interface stands on a network, named by a JOIN. A profile is a key with flat dotted values and no match block.

Inheritance. A subkey inherits every value of its ancestors and overrides those it names — per value name, wholesale: a list replaces a list, never appends. A present-but-empty value means none; an absent value means inherit. This is the same law as in Rules\: a subkey specialises its parent. A locally written profile may nest under one pushed by policy. Enabled = 0 makes a key and its subtree invisible.

Vocabulary. Bundles are the claims a network can make; each has an Offered that says whether to believe it. Every compiled default is "believe nothing, do nothing": a bare profile brings the link up and nothing else. Unknown value names refuse the generation.

BundleValueTypeMeaningDefault
AddressOffered0/1take the address the network offers (DHCPv4, IPv6 autoconfiguration)0
Familieslistipv4, ipv6: which families the bundle deals in at all; filters Static tooboth
StaticlistCIDR addresses, either familynone
LinkLocal0/1self-assign 169.254/16 while nobody answers; dropped when a lease arrives0
Temporary0/1add daily-rotating IPv6 privacy addresses beside the stable one0
OnExpiryDrop / Keepan offered address the network stops renewingDrop
RouteOffered0/1take the way out, and extra routes, the network offers0
Gatewaylistpinned way out, either familynone
Metricnumberrank of this interface's way out100 wired, 600 wireless
DnsOffered0/1take the servers and search domains the network offers, after our own0
Serverslistown servers, in ordernone
Domainslistdomains these servers answer fornone
Default0/1/absenttake names no domain claims; absent follows the default routeabsent
Exclusive0/1take all queries while at least addressed and supplying a DNS server0
HostnameOffered0/1adopt the network's name for us if Hostname is unset0
Announce0/1tell the network our name0
MtuOffered0/1take the packet size limit the network offers0
Valuenumber, 68+pin itleave alone

The Dns bundle is provisional. Verify the effective scope with resolv status; see name resolution for exclusivity and fallback conditions.

The laws of JOIN, whatever the profile says: the executor owns every IPv4 and non-link-local IPv6 address on a joined interface, and only routes carrying its own protocol tag; the kernel's IPv6 link-local address is left alone; exactly one place decides what a router advertisement means (the executor; the kernel's own handling is off); a link-local address is dropped the moment a real lease arrives; IPv6 lifetimes follow the RFCs with the two-hour floor; Route.Metric defaults by kind; the network's RequestedAddress is asked for first; a manual change to a joined interface lasts until the next reconcile; the executor re-derives state on restart.

Registry layout #

Machine\System\Network
    Hostname                     REG_SZ           operator
    Readiness                    REG_SZ           netd: absent | link | addressed | routed
    Duid                         REG_SZ           shared: DHCPv6 identifier, hex
    Rules\
        CurrentReportingLevel    REG_DWORD 1..6   (optional; absent = 1)
        RawPacket\               the wire-side layer's forest
            <rule>\
        Packet\                  the per-packet layer's forest
            <rule>\              one tree root
                <exception>\     a subkey: narrower region, same laws
                    ...
        Flow\                    the flow layer's forest
            <rule>\
        Interface\               the interface layer's forest (netd's)
            <rule>\
    Profiles\                    how an interface stands on a network
        <profile>\               flat dotted values, see Profiles
            <derived>\           a subkey inherits and overrides
    Interfaces\<id>\             the inventory, one key per interface seen
        ClientId                 REG_SZ           shared: DHCPv4 client identifier
        Status\                  netd-only: Name, Kind, Mac, Path, Driver,
                                 Verdict, Rule, Profile, Readiness,
                                 Network, LastNetwork
    Networks\<id>\               one key per network stood on
        Name, Trust              REG_SZ           operator
        RequestedAddress         REG_SZ           shared: IPv4 to ask for next
        Status\                  netd-only: Kind, Server, Gateway, Router,
                                 Prefixes, DnsServers, LastSeen, LastInterface
    Dns\                         name resolution's machine values, see name resolution

A rule key's name is its attribution handle and may not contain \ or /. The kernel reads RawPacket, Packet and Flow; Interface is read by netd, the interface layer's executor (see Layers); any other layer key is ignored by both. The kernel also reads the inventory — each interface's Status Network and the Name and Trust on the record it names — as the network context of the packet layers. Shared values are written by netd when absent and may be set by the operator; Status keys carry a descriptor that lets only netd write, so a hand edit is refused rather than silently reverted.

Rule values #

ValueTypeMeaning
ActionsREG_MULTI_SZThe action list, one expression per element. Absent or empty = NULL (abstain).
PriorityREG_DWORD / REG_QWORDCollation weight. Inherited by subkeys; a root defaults to 0.
EnabledREG_DWORD 0 or 10 disables the rule and its whole subtree. Default 1.
<Fact>.<Operator>see belowA condition. Any other value name is an error that refuses the generation.

The Rules key's own value #

ValueTypeMeaning
CurrentReportingLevelREG_DWORD 1..6REPORT(n) fires when n >= CurrentReportingLevel. Absent = 1 (everything fires); 6 silences all reports. Out of range refuses the generation.

Conditions #

A condition is a value named <Fact>.<Operator>. A rule matches when every condition holds; a condition over a fact the packet lacks is false (the absent-fact law).

Operators #

OperatorFamiliesValue
EqualallMembership: a scalar, or a list (REG_MULTI_SZ) meaning any of. Integers accept a-b ranges; addresses accept CIDR prefixes and (IPv4) a-b ranges.
GreaterThanintegerA single integer; strictly greater.
LessThanintegerA single integer; strictly less.
HasflagsA flag name or list; all listed bits set.
HasntflagsA flag name or list; all listed bits clear.
Presentall, and Tag.<name> / Counter.<name>1: the fact exists for this packet or flow; 0: it does not. The one operator that looks through the absent-fact law. On a fact its layer never has, it refuses the generation rather than becoming an always-true condition.

Integer values may be written as REG_DWORD, REG_QWORD, or as decimal strings; a list of integers is a REG_MULTI_SZ of decimal strings and ranges. Applying an operator a family does not support (GreaterThan on an address, Has on a port) refuses the generation.

Facts #

FactFamilyValuesPresent when
Directionstringin, outalways. Flow: the originator's side, for the flow's whole life
Interfacestringinterface name, e.g. eth0always. Flow, outbound: the route's device
EtherTypeintegernumber, or ipv4, ipv6, arpalways. Not a Flow fact (a flow's family is its addresses')
SrcMacMACaa:bb:cc:dd:ee:ffframe has an Ethernet header; at the IP seats outbound, the machine's own device address
DstMacMACaa:bb:cc:dd:ee:ffframe has an Ethernet header. Not a Flow fact
VlanintegerVLAN idthe frame is VLAN-tagged (device seats) or the interface is a VLAN device (IP seats)
SrcAddr, DstAddraddressexact (10.0.0.5, fd00::1), CIDR (10.0.0.0/8, fd00::/64), IPv4 range (10.0.0.1-10.0.0.99)IP packet
Protocolintegernumber, or tcp, udp, icmp, icmpv6, sctpIP packet
TtlintegerTTL / hop limitIP packet. Not a Flow fact
Dscpinteger0..63IP packet. Not a Flow fact
Fragmentinteger0 or 1IP packet (only ever 1 before defragmentation, i.e. at the RawPacket seat). Not a Flow fact
SrcPort, DstPortinteger0..65535TCP, UDP or SCTP
TcpFlagsflagsFIN, SYN, RST, PSH, ACK, URG, ECE, CWRTCP. Not a Flow fact
IcmpType, IcmpCodeintegerICMP / ICMPv6 type and codeICMP or ICMPv6
Lengthintegerpacket length in bytes at the seat (stack view)always. Not a Flow fact
FlowStatestringnew, established, related, invalid, untrackedPacket layer at its proper seat; never at the RawPacket or Flow layers
Relatedinteger0 or 1: the flow was expected by another (an ICMP error for a live flow, FTP data)Flow layer only
Time.Year, Time.Month, Time.DayOfMonth, Time.DayOfWeek, Time.Hour, Time.Minute, Time.Secondintegerwall clock, UTC; DayOfWeek is ISO (1 = Monday .. 7 = Sunday)always. In Flow, a consulted condition expires the sentence at its next flip
Start.Year, Start.Month, Start.DayOfMonth, Start.DayOfWeek, Start.Hour, Start.Minute, Start.Secondintegerthe wall clock when the flow began, UTCFlow layer only; fixed for the flow's life, never expires a sentence
Localstringprogram, kernel, shared, none: what stands at this machine's end of the flowFlow layer only; always present there
Local.UserSIDS-1-5-19, or a well-known name (SYSTEM, LocalService, NetworkService, Everyone, Administrators, Users, …)Flow, Local is program
Local.GroupSID setSIDs or well-known names; any of the token's enabled groups (deny-only groups are invisible; the logon SID is among them)Flow, Local is program
Local.Integrityintegera level, or untrusted, low, medium, high, systemFlow, Local is program
Local.ConfinementSIDthe confinement SIDFlow, the program is confined
Local.CapabilitySID setany of the confinement's capability SIDsFlow, the program is confined
Local.ServiceSIDa service name (resolvd), or its S-1-5-80-… SIDFlow, the program is a service
Local.Processstringthe process GUID, 8-4-4-4-12 hex (case-insensitive)Flow, Local is program
Remote, Remote.*as Localthe other end of the flow, when it is on this machine tooFlow, loopback flows only
Interface.Kindstringwired, wireless, loopback, tunnel, bridge, otherInterface layer only; always
Interface.Idstringthe stable interface id (the inventory key name)Interface layer only; always
Interface.MacMACaa:bb:cc:dd:ee:ffInterface layer only; the interface has a hardware address
Interface.Pathstringbus position, e.g. pci-0000:00:03.0Interface layer only; it is hardware
Interface.Driverstringkernel driverInterface layer only; it is hardware
Network.Idstringthe network record's key name under Networks\every layer: a network has been identified on the interface the packet crossed (see the network context)
Network.Namestringthe operator's Name on the recordevery layer; the record has one
Network.Truststringthe operator's Trust on the recordevery layer; the record has one
Network.Kindstringthe Interface.Kind the network was seen onInterface layer; a network has been identified
Tag.<name>integerthe flow tag's valuethe flow carries the tag (Packet and Flow layers; never RawPacket)
Counter.<name>[(...)]integera counter view, see belowthe packet has the view's key facts and a cell exists

Address families are strict: an IPv4 pattern never matches an IPv6 address and vice versa, so 0.0.0.0/0 does not swallow IPv6.

A Flow fact is one that is identical for every packet of the flow. The per-packet facts marked "not a Flow fact" are legal in a Flow rule but never present there, so the condition never holds; the viewer flags it. Related, Start.* and the identity facts are the reverse: never present outside Flow. Interface.* facts are for the Interface layer. Network.Id, Network.Name and Network.Trust are also available in the packet layers, as the table above and network context describe. A packet-only fact in an Interface rule cannot match. For the kinds netd currently reports, see its interface classification. Tag.* and Counter.* do not exist at the Interface layer at all — there is no store behind them — and refuse the generation.

Who is at this end #

Local says what answers at this machine's end of a flow: a program (a socket some process owns — the identity the kernel stamped on it at the last act that committed it: creation, bind, listen, connect, accept, or an explicit restamp), the kernel itself (resets, ICMP errors, neighbour discovery, tunnel outers, kernel sockets), shared (inbound multicast or broadcast, delivered to every socket bound to the port — one flow, many receivers), or none (nothing listens; the stack will refuse it). Only a program has Local.* facts, so Local.User.Present = 0 is "no program stands here".

Identity is decided once, at the flow's first judgment, and kept for the flow's life. A service thread acting for a client is the client (the effective identity governs, as it does for files); a listener handed to another program is governed by the program that last committed it. SIDs are written as S-1-…; a user or group may instead be a well-known name, a service its name — the name is turned into the service's SID exactly as the service's token was minted, so the rule matches the token, not a string. A misspelt name refuses the generation rather than quietly matching nothing.

Counter views #

Counter.<name> reads the stream <name> that some rule's COUNT writes. In parentheses, in any order, at most one of each:

ArgumentFormMeaning
window<n>s, <n>m, <n>h, <n>d — at most 1dSliding window; omitted = the cumulative total since the cell was created.
keySrcAddr, DstAddr, Interface, or a +-compound (SrcAddr+DstAddr)Which facts partition the count; omitted = one global cell.

Examples: Counter.dns (total, global); Counter.dns(10s) (last ten seconds, global); Counter.dns(SrcAddr) (total, per source); Counter.dns(1h, SrcAddr+DstAddr) (last hour, per source–destination pair). A view over a stream that no rule anywhere writes refuses the generation; a stream nobody reads is fine. Windows are approximated by eight buckets, so a value can be up to an eighth of a window stale.

Actions #

Actions is a list of expressions. Names are case-insensitive; whitespace is ignored. A rule's actions may contain any mix; at most one verdict results (the strictest listed).

ExpressionSpeciesMeaning
NULLabstentionNothing. A rule whose actions yield no verdict abstains.
PASSverdictThis layer approves.
DROPverdictRefuse silently.
REJECT / REJECT(Refused)verdictRefuse; look like nothing is listening — TCP RST, else ICMP port-unreachable.
REJECT(Prohibited)verdictRefuse; say policy did it — ICMP admin-prohibited for every protocol.
PROMPT(Handler[, Fallback])deferralAsk a userspace handler; on no answer apply Fallback (an action expression, nesting up to 4 deep). No handler transport exists in this release: the fallback applies immediately and the prompt is recorded.
TAG(Name, Set[, n])effectSet flow tag Name to n (default 1).
TAG(Name, Add[, n])effectAdd n (default 1) to the tag; an absent tag counts as 0 first.
TAG(Name, Clear)effectRemove the tag; it reads as absent afterwards.
COUNT(Name[, n])effectEmit n (default 1) into stream Name.
COUNT(Name, Length)effectEmit the packet's byte length — the bandwidth primitive.
REPORT(level)effectEmit an ntfe.verdict.reported audit event, level 1..5, if the level clears CurrentReportingLevel. One report per rule per evaluation, at the highest level listed.
JOIN(profile)verdict, Interface layerBring the interface up and stand in the named profile: a path under Profiles\, /- or \-separated.
IGNOREverdict, Interface layerNever touch the interface; something else owns it.
DOWNverdict, Interface layerKeep the interface administratively down.

The three interface verdicts are legal only in the Interface layer, and that layer speaks nothing but them, NULL and REPORT; either way round refuses the generation. Their strictness order is DOWN > IGNORE

JOIN. JOIN must name a profile that exists (a path that names no key refuses the generation); naming a disabled profile makes the rule abstain, as if its action were NULL.

Unknown action names, wrong argument counts, negative or non-integer operands, unminted REJECT kinds, and a TAG operation other than the three above all refuse the generation.

Where a REJECT can speak #

Everywhere, for IP traffic. Inbound, the refusal goes back to the peer. Outbound, the answer the peer would have sent is delivered to the local socket, so the program fails at once — a TCP connect, or the next call on a connected UDP socket — with connection refused for Refused (a reset for TCP, a port unreachable for UDP and the rest), and for Prohibited with host unreachable over IPv4 or permission denied over IPv6. Only a packet with no refusal vocabulary — ARP and other non-IP frames, a broadcast or multicast destination, a fragment — is applied as a DROP and counted as degraded; the verdict event still says REJECT and names the kind. The refusals PNP sends pass its own seats unjudged.

In the Flow layer a REJECT sentence answers every later packet of the flow the same way, so a retransmitted SYN gets its reset too — from the sentence, or, where refusing the first packet took the new flow with it, from a fresh judgment of the retransmit as a new flow. When the refused packet belongs to an established TCP connection (a flow re-judged after a policy change or at a time edge), the other end is torn down as well: the refused packet is turned into a reset and sent where it was going, so both sockets fail at once. New flows and UDP have no far end to tear down.

Layers #

RawPacketPacketFlow
Judgedat the device seats, for all traffic, per packetonce per traversal, at the richest seat, per packetonce per flow (per local endpoint), at the IP seats, on the flow's first packet
Orderfirst inbound, last outboundbetweenlast inbound (after Packet), first outbound (before Packet)
FlowStatenever (the seat stands before conntrack)yesnever (the layer is the judgment of a flow)
Related, Start.*neverneveryes
Local, Local.*, Remote.*neverneveryes (Remote on loopback only)
Network.Id, Network.Name, Network.Trustyesyesyes
Per-packet facts (Length, TcpFlags, Fragment, Ttl, Dscp, EtherType, DstMac)yesyesnever
Tag.<name> readsnevertags RawPacket or Packet rules writeany tag
TAG writesyesyesyes
Fragmentmay be 1always 0—
Effects runper packetper packetper evaluation of the flow
Verdict scopethe packetthe packetthe flow: cached as its sentence

A rule conditioned on a fact its layer never has is legal but can never match; the viewer flags it. A Packet or RawPacket rule that reads a tag a Flow rule writes is a downward read and refuses the generation.

The interface layer #

Rules\Interface is the fourth layer, and the one the kernel does not read. Its subject is an interface, not a packet: a rule is judged for each interface (loopback excepted) whenever an interface appears or changes, whenever a network is identified on it, and whenever a generation lands. Its executor is netd, which builds and judges the forest with the same engine the kernel uses, so a rule means the same thing in every layer.

Interface
Judgedper interface, by netd, on interface and generation change
FactsInterface, Interface.*, Network.* (Network.Id, Network.Name and Network.Trust are the packet layers' too; the rest is this layer's alone)
VerdictsJOIN(profile), IGNORE, DOWN; strictness in that order, rising
EffectsREPORT only
BackstopIGNORE: an interface no rule speaks for is left as the kernel left it
Resultan interface is in exactly one profile, or ignored, or down

The collation laws are the packet layers': highest priority wins, ties go to the strictest verdict, a subkey is an exception, an abstaining rule hands up its parentage. One case has no packet-layer analogue: two rules tied on priority naming different profiles for one interface. That is a conflict, not a choice. On a runtime reload, a tie affecting an existing interface refuses the generation; net status names both rules. At startup, or when a new interface appears, that interface is ignored with a tie warning instead. See netd's conflict handling.

Executor independence. A generation is one registry state read by two executors. Each validates and refuses its own layers on its own: a dangling JOIN keeps netd on its last good interface forest and never stalls the firewall, and a bad Flow rule never stops an interface joining.

The executor's own traffic. Joining needs netd to send and receive DHCP and router discovery, and PNP grants that nothing implicitly: the permission is the dhcp-client, icmpv6-housekeeping and dhcpv6-client rules of the baseline below, ordinary and deletable. netd cannot yet read the verdict stream to name a rule that refused it (the stream has one reader, the viewer); net status reports an unanswered request as a warning.

Sentences #

A sentence caches the Flow verdict. Later packets use it without a new evaluation event until the policy generation changes or a consulted Time.* condition changes. A fresh judgment runs the effects again. Start.* stays fixed and does not expire the sentence. Loopback has one sentence per local endpoint and must pass both.

For exact expiry rules (including daily reevaluation of calendar fields), cache-allocation failure and event behavior, see The Flow layer and Evaluation. Those chapters retain the implementation detail; use this section to choose live-time versus connection-start conditions.

The network context #

Which network the machine is on is one fact, told once. netd identifies the network on a link and writes the record's id to the interface's Status Network; the kernel reads that, and the Name and Trust on the record it names, into a table keyed by interface, and every traversal carries its interface's entry as Network.Id, Network.Name and Network.Trust. So the three facts the interface layer conditions on to choose a profile are the same three a packet rule conditions on to open or close a door, read from the same record:

Rules\Flow\no-ssh               Direction.Equal = in
                                 Protocol.Equal = tcp, DstPort.Equal = 22
                                 Actions = DROP
Rules\Flow\no-ssh\home          Network.Trust.Equal = home
                                 Actions = PASS

is "SSH answers only on the network I called home", and it is true on every interface at once: a wired card at home and a radio at a cafe each carry their own context, and a flow sees the context of the interface it actually uses.

The facts are absent on an interface no network has been identified on — before the first offer, after the carrier goes, on the loopback, on an IGNOREd or DOWN interface — so a rule about a network is simply false there and the rules that say nothing about networks apply unchanged: an unrecognised network gets the baseline, never a door opened for a network that is not there. Network.Id.Present = 0 is the honest "not on any known network".

A change of network is a change of policy. When the context of any interface changes — a network identified, the carrier lost, the operator editing Trust — the kernel publishes a new generation, and every flow is re-judged on its next packet exactly as after a rule change: a connection the new context forbids is refused then, with the same REJECT teardown, and one it now permits goes through. netd rewriting an interface's Status without changing its network costs nothing; a generation is published only when the table differs. The context is not policy and cannot refuse a generation: a record the kernel could not read is an interface without a context.

Trust is the operator's word, exactly as written, with no vocabulary yet: home, corporate, untrusted are conventions, and a rule that conditions on it is stating that the operator accepts the identification. It is not evidence that the network has been authenticated.

Limits #

These kernel limits can cause a refused generation or a counted refusal. netd has its own registry-read depth limit; do not assume a packet-layer limit describes every executor.

LimitValueWhen exceeded
Distinct tags per flow64the write is refused and counted
Keys per counter table4096idle keys are reaped; if none are idle the new key is refused and counted
Windows per (stream, key)8the generation is refused
Longest window1 daythe generation is refused
Rule nesting depth12the generation is refused
Rules per layer4096the generation is refused
Attribution path in events96 bytestruncated
Tags reported per flow in the flows dump8the rest are counted, not listed

The development baseline #

The rules below illustrate the baseline seed policy, not the complete policy of every image. The compiled-in backstop is DROP in every layer; each allow rule is a visible, deletable exception.

Service-specific seeds add their own rules. The Experimental edition's gxwi-network seed admits GXWI on TCP 7780; see the desktop quick start. Inspect the configured rules and verify kernel acceptance with the policy-checking workflow before deciding which services a machine exposes. The development PNP viewer uses port 8081 and needs its own restricted access path.

Rules\RawPacket:

RuleConditionsActions
all—PASS

Rules\Packet — passes every tracked packet through to Flow, and the untracked housekeeping a host needs:

RuleConditionsActions
trackedFlowState.Equal = new, established, relatedPASS
outbound-okDirection.Equal = outPASS
loopbackInterface.Equal = loPASS
arpEtherType.Equal = arpPASS
icmpv6-housekeepingProtocol.Equal = icmpv6, IcmpType.Equal = 130-137, 143PASS
dhcp-clientProtocol.Equal = udp, SrcPort.Equal = 67, DstPort.Equal = 68PASS

Rules\Flow — the decisions:

RuleConditionsActions
outbound-okDirection.Equal = outPASS
loopbackInterface.Equal = loPASS
dhcpv6-clientDirection.Equal = in, Protocol.Equal = udp, SrcAddr.Equal = fe80::/10, SrcPort.Equal = 547, DstPort.Equal = 546PASS

An inbound flow with no matching allow rule meets the Flow backstop, once, on its first packet; untracked inbound packets with no matching allow rule meet the Packet backstop.

Profiles and Rules\Interface — every wired interface joins the network it is plugged into, taking what it offers:

KeyValues
Profiles\defaultAddress.Offered = 1, Address.LinkLocal = 1, Route.Offered = 1, Dns.Offered = 1
Rules\Interface\wiredInterface.Kind.Equal = wired, Priority = 10, Actions = JOIN(default)

Wireless is not in the baseline until a supplicant exists. An interface no rule speaks for meets the Interface backstop, IGNORE.

Worked examples #

These blocks describe registry layouts, not shell commands or complete replacement policies. Adapt the addresses, ports, names, priorities and profile paths to your machine. A JOIN target must already exist; examples are evaluated alongside every existing rule, so inspect the baseline and competing priorities before applying them. Preserve a recovery path, then verify accepted policy and an actual connection afterwards.

An exception under a broad rule — drop all inbound except SSH from the LAN, and tell other SSH sources that policy said no:

Rules\Packet\no-inbound            Direction.Equal = in
                                   Actions = DROP
Rules\Packet\no-inbound\ssh        DstPort.Equal = 22
                                   Actions = REJECT(Prohibited)
Rules\Packet\no-inbound\ssh\lan    SrcAddr.Equal = 10.0.0.0/8
                                   Actions = PASS

A flow tag read on the reply — mark DNS queries, report on the replies of marked flows:

Rules\Packet\tag-dns        Protocol.Equal = udp, DstPort.Equal = 53
                            Actions = TAG(dnsq, Add)
Rules\Packet\tagged-reply   Protocol.Equal = udp, SrcPort.Equal = 53
                            Tag.dnsq.GreaterThan = 0
                            Actions = REPORT(4)

Byte accounting per interface — count outbound bytes and refuse a source that pushes more than 100 MB in a minute:

Rules\Packet\egress-bytes   Direction.Equal = out
                            Actions = COUNT(egress, Length)
Rules\Packet\egress-cap     Direction.Equal = out
                            Counter.egress(1m, SrcAddr).GreaterThan = 104857600
                            Actions = DROP

A connection-level allow — let the machine connect out, accept SSH in from the LAN, and refuse every other inbound connection with a reset, each decided once per flow:

Rules\Flow\outbound-ok      Direction.Equal = out
                            Actions = PASS
Rules\Flow\inbound          Direction.Equal = in
                            Actions = REJECT
Rules\Flow\inbound\ssh-lan  Protocol.Equal = tcp, DstPort.Equal = 22
                            SrcAddr.Equal = 10.0.0.0/8
                            Actions = PASS

A curfew that lets downloads finish — no new outbound connections between 22:00 and 06:00 UTC, existing ones run on:

Rules\Flow\curfew           Direction.Equal = out
                            Start.Hour.Equal = 22-23, 0-5
                            Priority = 10
                            Actions = REJECT(Prohibited), REPORT(3)

Written with Time.Hour instead of Start.Hour, the same rule cuts every running outbound connection at 22:00 — on its next packet, with an ICMP admin-prohibited — and the report says which rule did it.

A static server as an exception — every wired interface takes what the network offers, except the card in slot 3, which stands in a derived profile that changes only the address and the way out:

Profiles\default                 Address.Offered = 1, Address.LinkLocal = 1
                                 Route.Offered = 1, Dns.Offered = 1
Profiles\default\db1             Address.Offered = 0, Address.Static = 10.0.0.5/24
                                 Route.Offered = 0, Route.Gateway = 10.0.0.1
Rules\Interface\wired            Interface.Kind.Equal = wired
                                 Actions = JOIN(default)
Rules\Interface\wired\db1        Interface.Path.Equal = pci-0000:00:03.0
                                 Actions = JOIN(default/db1)

default/db1 still inherits Dns.Offered, but that does not prove a server is available after offered address acquisition stops. Check resolv status and pin Dns.Servers if this configuration needs it.

The laptop — a network-dependent selection example, not a working Wi-Fi association procedure. A supplicant and wireless network-name identification are unfinished; the baseline leaves wireless unmanaged. Once the link and identity exist, rules can choose among three profiles:

Rules\Interface\radio            Interface.Kind.Equal = wireless
                                 Actions = JOIN(untrusted)
Rules\Interface\radio\home       Network.Name.Equal = palfrey-home
                                 Actions = JOIN(home)
Rules\Interface\radio\office     Network.Trust.Equal = corporate
                                 Actions = JOIN(corp)

Network.Name and Network.Trust are what the operator wrote on the record under Networks\; until a network has been identified on the link they are absent, so the radio stands in untrusted first. The same two facts open the doors, in the flow layer:

Rules\Flow\no-inbound           Direction.Equal = in
                                 Actions = DROP
Rules\Flow\no-inbound\at-home   Network.Trust.Equal = home
                                 Protocol.Equal = tcp
                                 DstPort.Equal = 22, 5900
                                 Actions = PASS

Walk into the cafe and the record on the other side of the radio is a different one, with no Trust written: the exception is false, the parent drops the SSH traffic on its next packet. DROP is silent; the reset behavior described for REJECT does not apply to this example.

A card that stays dark, and one another program owns:

Rules\Interface\dead-card        Interface.Id.Equal = 3f2a1b8e-…
                                 Priority = 100
                                 Actions = DOWN
Rules\Interface\tap              Interface.Equal = tap0
                                 Actions = IGNORE

Connection rate limiting — count connections, not packets, by counting in the flow layer:

Rules\Flow\conn-count       Direction.Equal = in, Protocol.Equal = tcp
                            Actions = COUNT(conns)
Rules\Flow\conn-flood       Direction.Equal = in, Protocol.Equal = tcp
                            Counter.conns(1m, SrcAddr).GreaterThan = 100
                            Actions = DROP

Edit this page