Project

General

Profile

Regression #16672 » matching-anchor-bug.sh

Arthur Wiebe, 01/29/2026 02:51 AM

 
1
#!/usr/local/bin/bash
2

    
3
# This script demonstrates a potential pf bug on pfSense 24.11+ on x86 hardware.
4
#
5
# The bug is that if a tag is applied to a packet in multiple nested anchors,
6
# it will not be applied in a tagged pass rule
7

    
8
# --- Configuration ---
9
DESTINATION_TEST_IP="208.123.73.78"
10
TABLE_NAME="example_dst_table"
11
TAG_NAME="example_tag"
12
ANCHOR_PARENT="userrules"
13
ANCHOR1="bug_anchor1"
14
ANCHOR2="bug_anchor2"
15
RULES_FILE="/tmp/bug_rules.txt"
16

    
17
# --- Cleanup previous runs ---
18
# Clean up to ensure a fresh state.
19
# These commands will fail if the anchors/tables don't exist, which is fine.
20
pfctl -a $ANCHOR_PARENT/$ANCHOR1 -F all 2>/dev/null
21
pfctl -a $ANCHOR_PARENT/$ANCHOR2 -F all 2>/dev/null
22
pfctl -t $TABLE_NAME -T flush 2>/dev/null
23

    
24
echo "Cleaned up any previous rules and tables."
25

    
26
# 1. Create an IP address table
27
echo "1. Creating table '$TABLE_NAME' with ${DESTINATION_TEST_IP}..."
28
pfctl -t $TABLE_NAME -T add $DESTINATION_TEST_IP
29
echo "Table '$TABLE_NAME' created."
30
pfctl -t $TABLE_NAME -T show
31

    
32
# 2. Create the anchor rules in a temporary file
33
echo "2. Creating temporary rules file at $RULES_FILE..."
34
if [[ "$1" == "single-anchor" ]]; then
35
cat > $RULES_FILE <<EORULES
36
# Demonstrate that a single anchor works
37
anchor "$ANCHOR1" {
38
    match in log to <$TABLE_NAME> tag "$TAG_NAME" label "$ANCHOR1"
39
}
40
EORULES
41
else
42
cat > $RULES_FILE <<EORULES
43
# In each anchor, create a match and log rule that applies the tag.
44
anchor "$ANCHOR1" {
45
    match in log to <$TABLE_NAME> tag "$TAG_NAME" label "$ANCHOR1"
46
}
47
anchor "$ANCHOR2" {
48
    match in log to <$TABLE_NAME> tag "$TAG_NAME" label "$ANCHOR2"
49
}
50
EORULES
51
fi
52

    
53
# Load the rules into the parent anchor
54
echo "3. Loading rules into parent anchor '${ANCHOR_PARENT}/*'"
55
pfctl -a $ANCHOR_PARENT -f $RULES_FILE
56

    
57
echo "--- Rules Loaded ---"
58
echo "The following rules have been loaded under the '$ANCHOR_PARENT' anchor:"
59
pfctl -a $ANCHOR_PARENT -s rules
60

    
61
echo "--- Manual Step Required ---"
62
echo "Create an allow rule on your LAN interface in pfSense, and allow any traffic tagged with \"$TAG_NAME\"."
63
echo "Enable logging on this rule to help with demonstrating the behaviour below."
64
echo "----------------------------"
65

    
66
echo "--- Setup Complete ---"
67
echo "To test this, you must generate traffic from your LAN to $DESTINATION_TEST_IP."
68
echo "For example, from a client computer on your LAN, run:"
69
echo "ping $DESTINATION_TEST_IP"
70

    
71
echo "To observe the bug, check the firewall logs on pfSense."
72
echo "You can use the following command to filter for the relevant log entries:"
73
echo "tail -F /var/log/filter.log | grep $DESTINATION_TEST_IP"
74

    
75
echo "--- Expected Behavior (Demonstrating Bug) ---"
76
echo "When you generate traffic, you should see log entries from the firewall rule labels '$ANCHOR1' and '$ANCHOR2'."
77
echo "This confirms that the traffic is being matched and tagged in both anchors."
78
echo "However, you will NOT see any log entries for the pass rule you created in the manual step above."
79
echo "This demonstrates the bug: the 'pass' rule is not being hit, and the traffic will likely be blocked by a default deny rule instead of being passed."
(1-1/3)