|
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."
|