-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathfirewall.sh
More file actions
executable file
·316 lines (265 loc) · 10.8 KB
/
firewall.sh
File metadata and controls
executable file
·316 lines (265 loc) · 10.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
#!/bin/bash
# Albator Firewall Configuration Script
# Enhanced with error handling, logging, and verification
set -euo pipefail # Exit on error, undefined vars, pipe failures
# Source common utilities
source "$(dirname "$0")"/utils.sh
# Configuration
SCRIPT_NAME="firewall.sh"
LOG_FILE="/tmp/albator_firewall.log"
BACKUP_DIR="/tmp/albator_backup/firewall"
DRY_RUN=${DRY_RUN:-false}
ALBATOR_TEST_ALLOW_DRYRUN_NO_SUDO=${ALBATOR_TEST_ALLOW_DRYRUN_NO_SUDO:-false}
FIREWALL_CMD="${FIREWALL_CMD:-/usr/libexec/ApplicationFirewall/socketfilterfw}"
# Function to backup current firewall settings
backup_firewall_settings() {
show_progress "Backing up current firewall settings..."
mkdir -p "$BACKUP_DIR"
local backup_file="$BACKUP_DIR/firewall_settings_$(date +%Y%m%d_%H%M%S).backup"
{
echo "# Firewall backup created on $(date)"
echo "GLOBAL_STATE=$(sudo $FIREWALL_CMD --getglobalstate 2>/dev/null || echo 'unknown')"
echo "BLOCK_ALL=$(sudo $FIREWALL_CMD --getblockall 2>/dev/null || echo 'unknown')"
echo "STEALTH_MODE=$(sudo $FIREWALL_CMD --getstealthmode 2>/dev/null || echo 'unknown')"
echo "LOGGING_MODE=$(sudo $FIREWALL_CMD --getloggingmode 2>/dev/null || echo 'unknown')"
echo "ALLOW_SIGNED=$(sudo $FIREWALL_CMD --getallowsigned 2>/dev/null || echo 'unknown')"
echo "ALLOW_SIGNED_APP=$(sudo $FIREWALL_CMD --getallowsignedapp 2>/dev/null || echo 'unknown')"
} > "$backup_file"
log "INFO" "Firewall settings backed up to $backup_file"
}
# Function to apply firewall setting with verification
apply_firewall_setting() {
local setting_flag=$1
local setting_value=$2
local description=$3
local verification_flag=$4
local expected_output=$5
show_progress "Configuring: $description"
if [[ "$DRY_RUN" == "true" ]]; then
show_warning "DRY RUN: Would run: sudo $FIREWALL_CMD $setting_flag $setting_value"
record_plan_action "firewall" "$description" "sudo $FIREWALL_CMD $setting_flag $setting_value"
return 0
fi
local pre_value
pre_value=$(sudo "$FIREWALL_CMD" "$verification_flag" 2>/dev/null || echo "UNKNOWN")
if [[ "$pre_value" == *"$expected_output"* ]]; then
show_success "$description already compliant"
record_noop "$description already compliant"
return 0
fi
# Apply the setting
if sudo "$FIREWALL_CMD" "$setting_flag" "$setting_value" 2>>"$LOG_FILE"; then
# Verify the setting was applied
local current_value
current_value=$(sudo "$FIREWALL_CMD" "$verification_flag" 2>/dev/null || echo "FAILED")
if [[ "$current_value" == *"$expected_output"* ]]; then
show_success "$description"
local rollback_value
if [[ "$setting_value" == "on" ]]; then rollback_value="off"; else rollback_value="on"; fi
record_rollback_change "$setting_flag" "$description" "sudo $FIREWALL_CMD $setting_flag $rollback_value"
return 0
else
show_error "Failed to verify $description (expected: $expected_output, got: $current_value)"
return 1
fi
else
show_error "Failed to apply $description"
return 1
fi
}
# Function to check current firewall status
check_firewall_status() {
show_progress "Checking current firewall status..."
local global_state
global_state=$(sudo "$FIREWALL_CMD" --getglobalstate 2>/dev/null || echo "unknown")
if [[ "$global_state" == *"enabled"* ]]; then
show_success "Firewall is currently enabled"
record_noop "Firewall already enabled"
return 0
elif [[ "$global_state" == *"disabled"* ]]; then
show_warning "Firewall is currently disabled"
return 1
else
show_error "Unable to determine firewall status: $global_state"
return 2
fi
}
# Main firewall configuration function
configure_firewall() {
local errors=0
show_progress "Starting firewall configuration..."
# Check if firewall command exists
if [[ "$FIREWALL_CMD" == /* ]]; then
if [[ ! -x "$FIREWALL_CMD" ]]; then
show_error "Firewall command not found: $FIREWALL_CMD"
return 1
fi
elif ! command -v "$FIREWALL_CMD" >/dev/null 2>&1; then
show_error "Firewall command not found in PATH: $FIREWALL_CMD"
return 1
fi
# Backup current settings
backup_firewall_settings
# Check current status
check_firewall_status || true # Don't fail if disabled
# Enable the firewall
apply_firewall_setting "--setglobalstate" "on" "Application Layer Firewall" "--getglobalstate" "enabled" || ((errors++))
# Configure firewall settings
apply_firewall_setting "--setallowsigned" "off" "Allow signed applications" "--getallowsigned" "disabled" || ((errors++))
apply_firewall_setting "--setallowsignedapp" "off" "Allow signed applications (app-specific)" "--getallowsignedapp" "disabled" || ((errors++))
apply_firewall_setting "--setblockall" "on" "Block all incoming connections" "--getblockall" "enabled" || ((errors++))
apply_firewall_setting "--setstealthmode" "on" "Stealth mode" "--getstealthmode" "enabled" || ((errors++))
apply_firewall_setting "--setloggingmode" "on" "Firewall logging" "--getloggingmode" "enabled" || ((errors++))
return $errors
}
# Function to verify all firewall settings
verify_firewall_settings() {
local errors=0
show_progress "Verifying firewall configuration..."
# Verification tests
local tests=(
"--getglobalstate:enabled:Firewall enabled"
"--getblockall:enabled:Block all incoming enabled"
"--getstealthmode:enabled:Stealth mode enabled"
"--getloggingmode:enabled:Logging enabled"
"--getallowsigned:disabled:Allow signed disabled"
"--getallowsignedapp:disabled:Allow signed apps disabled"
)
for test in "${tests[@]}"; do
IFS=':' read -r flag expected description <<< "$test"
local actual
actual=$(sudo "$FIREWALL_CMD" "$flag" 2>/dev/null || echo "FAILED")
if [[ "$actual" == *"$expected"* ]]; then
show_success "✓ $description"
else
show_error "✗ $description (expected: $expected, got: $actual)"
((errors++))
fi
done
return $errors
}
# Function to display firewall status summary
display_firewall_summary() {
show_progress "Firewall Configuration Summary:"
echo "================================"
local settings=(
"--getglobalstate:Global State"
"--getblockall:Block All Incoming"
"--getstealthmode:Stealth Mode"
"--getloggingmode:Logging Mode"
"--getallowsigned:Allow Signed"
"--getallowsignedapp:Allow Signed Apps"
)
for setting in "${settings[@]}"; do
IFS=':' read -r flag description <<< "$setting"
local value
value=$(sudo "$FIREWALL_CMD" "$flag" 2>/dev/null || echo "ERROR")
printf "%-20s: %s\n" "$description" "$value"
done
echo "================================"
}
# Function to test firewall functionality
test_firewall() {
show_progress "Testing firewall functionality..."
# Test if firewall is blocking connections (basic test)
if command -v nc >/dev/null 2>&1; then
show_progress "Testing with netcat (if available)..."
# This is a basic test - in a real scenario you'd want more comprehensive testing
show_warning "Firewall functionality testing requires manual verification"
else
show_warning "netcat not available for firewall testing"
fi
# Check firewall log
local log_path="/var/log/appfirewall.log"
if [[ -f "$log_path" ]]; then
show_success "Firewall log file exists: $log_path"
local recent_entries
recent_entries=$(tail -5 "$log_path" 2>/dev/null | wc -l)
show_progress "Recent log entries: $recent_entries"
else
show_warning "Firewall log file not found: $log_path"
fi
}
# Main execution
main() {
echo "Albator Firewall Configuration Script"
echo "====================================="
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
--dry-run)
DRY_RUN=true
show_warning "Running in dry-run mode"
shift
;;
--test)
TEST_MODE=true
shift
;;
--help)
echo "Usage: $0 [--dry-run] [--test] [--help]"
echo " --dry-run Show what would be done without making changes"
echo " --test Include firewall functionality tests"
echo " --help Show this help message"
exit 0
;;
*)
show_error "Unknown option: $1"
exit 1
;;
esac
done
# Initialize logging
mkdir -p "$(dirname "$LOG_FILE")"
log "INFO" "Starting firewall configuration script"
init_script_state
# Check against configured baseline version
local macos_version
macos_version=$(sw_vers -productVersion)
local min_macos
min_macos=$(get_min_macos_version)
if [[ "$macos_version" != "$min_macos"* ]]; then
show_warning "Configured baseline is macOS >= $min_macos, detected: $macos_version"
fi
# Check for sudo privileges
if ! sudo -n true 2>/dev/null; then
if [[ "$DRY_RUN" == "true" && "$ALBATOR_TEST_ALLOW_DRYRUN_NO_SUDO" == "true" ]]; then
show_warning "Proceeding in dry-run test mode without sudo"
else
show_error "This script requires sudo privileges"
exit 1
fi
fi
# Run configuration
local config_errors=0
configure_firewall || config_errors=$?
# Run verification
local verify_errors=0
if [[ "$DRY_RUN" == "true" ]]; then
show_warning "Skipping verification in dry-run mode"
else
verify_firewall_settings || verify_errors=$?
fi
# Display summary
display_firewall_summary
# Run tests if requested
if [[ "${TEST_MODE:-false}" == "true" ]]; then
test_firewall
fi
# Summary
local total_errors=$((config_errors + verify_errors))
echo ""
echo "====================================="
if [[ $total_errors -eq 0 ]]; then
show_success "Firewall configuration completed successfully!"
log "INFO" "Firewall configuration completed successfully"
exit_with_status 0
else
show_error "Firewall configuration completed with $total_errors errors"
show_error "Check log file: $LOG_FILE"
log "ERROR" "Firewall configuration completed with $total_errors errors"
exit_with_status "$total_errors"
fi
}
# Run main function with all arguments
main "$@"