-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmsctl
More file actions
executable file
·188 lines (165 loc) · 5.29 KB
/
Copy pathmsctl
File metadata and controls
executable file
·188 lines (165 loc) · 5.29 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
#!/bin/sh
# msctl — matchstick firewall control.
# Wraps matchstick (the compiler) and nft (the runtime) for
# day-to-day firewall operations.
set -e
MATCHSTICK="${MATCHSTICK:-matchstick}"
NFT="${NFT:-nft}"
CONFIG="${MATCHSTICK_CONFIG:-/etc/matchstick/firewall.lua}"
TABLE="${MATCHSTICK_TABLE:-matchstick}"
FAMILY="${MATCHSTICK_FAMILY:-inet}"
usage() {
cat >&2 <<EOF
msctl — matchstick firewall control
Usage: msctl <command> [args]
Commands:
enable Apply config (alias: start, apply, reload)
disable Remove all matchstick rules (alias: stop)
status Show running rules
check Validate config without applying
diff Diff running rules vs config
edit Edit config, validate, and apply
show [sub] Visualize config:
matrix Zone policy grid
rules <src> <dst> Rules for a zone pair
topology [format] Diagram (ascii, dot, d2, mermaid)
render Print nftables text that would be applied
json Full state as JSON
sysctl Derived sysctl settings
version Print build info
Environment:
MATCHSTICK_CONFIG Config file (default: $CONFIG)
MATCHSTICK_TABLE Table name (default: $TABLE)
EDITOR Editor for 'edit' (default: vi)
EOF
exit 1
}
require_nft() {
if ! command -v "$NFT" >/dev/null 2>&1; then
echo "error: nft not found. Install nftables." >&2
exit 1
fi
}
require_root() {
if [ "$(id -u)" -ne 0 ]; then
echo "error: must be root" >&2
exit 1
fi
}
require_config() {
if [ ! -f "$CONFIG" ]; then
echo "error: config not found: $CONFIG" >&2
exit 1
fi
}
cmd_enable() {
require_root
require_config
require_nft
# Validate config
echo "checking config..." >&2
"$MATCHSTICK" check "$CONFIG" >/dev/null
# Apply sysctls
local sysctls
sysctls=$("$MATCHSTICK" show sysctl "$CONFIG" 2>/dev/null)
if [ -n "$sysctls" ]; then
echo "applying sysctls..." >&2
echo "$sysctls" | while IFS='= ' read -r key value; do
[ -z "$key" ] && continue
local path="/proc/sys/$(echo "$key" | tr '.' '/')"
if [ -w "$path" ]; then
echo "$value" > "$path" 2>/dev/null || \
echo "warning: sysctl $key: failed" >&2
fi
done
fi
# Render and apply atomically via nft
echo "applying rules..." >&2
local json
json=$("$MATCHSTICK" render --json "$CONFIG" 2>/dev/null)
if [ -z "$json" ]; then
echo "error: render failed" >&2
exit 1
fi
# Validate first (dry-run)
echo "$json" | $NFT -j -c -f - || {
echo "error: nftables validation failed" >&2
exit 1
}
# Apply
echo "$json" | $NFT -j -f - || {
echo "error: nftables apply failed" >&2
exit 1
}
echo "ok: rules applied"
}
cmd_disable() {
require_root
require_nft
$NFT delete table "$FAMILY" "$TABLE" 2>/dev/null && \
echo "deleted table $FAMILY $TABLE" || \
echo "table $FAMILY $TABLE not found"
$NFT delete table "$FAMILY" "${TABLE}_nat" 2>/dev/null && \
echo "deleted table $FAMILY ${TABLE}_nat" || \
echo "table $FAMILY ${TABLE}_nat not found"
}
cmd_status() {
require_nft
$NFT list table "$FAMILY" "$TABLE" 2>/dev/null || true
$NFT list table "$FAMILY" "${TABLE}_nat" 2>/dev/null || true
if ! $NFT list table "$FAMILY" "$TABLE" >/dev/null 2>&1; then
echo "matchstick is not active (table $FAMILY $TABLE not found)"
fi
}
cmd_check() {
require_config
"$MATCHSTICK" check "$CONFIG"
}
cmd_diff() {
require_nft
require_config
{
$NFT list table "$FAMILY" "$TABLE" 2>/dev/null || true
$NFT list table "$FAMILY" "${TABLE}_nat" 2>/dev/null || true
} | "$MATCHSTICK" diff "$CONFIG" -
}
cmd_edit() {
require_root
require_config
local editor="${EDITOR:-vi}"
local tmp
tmp=$(mktemp "${CONFIG}.edit.XXXXXX")
cp "$CONFIG" "$tmp"
if $editor "$tmp" && "$MATCHSTICK" check "$tmp"; then
cp "$tmp" "$CONFIG"
rm -f "$tmp"
"$MATCHSTICK" apply "$CONFIG"
else
echo "config unchanged (validation failed or editor exited with error)" >&2
rm -f "$tmp"
exit 1
fi
}
cmd_show() {
require_config
case "${1:-matrix}" in
matrix) "$MATCHSTICK" show matrix "$CONFIG" ;;
rules) shift; "$MATCHSTICK" show rules "$CONFIG" "$@" ;;
topology) "$MATCHSTICK" show topology "$CONFIG" --format="${2:-ascii}" ;;
render) "$MATCHSTICK" render "$CONFIG" ;;
json) "$MATCHSTICK" show json "$CONFIG" ;;
sysctl) "$MATCHSTICK" show sysctl "$CONFIG" ;;
*) echo "error: unknown show subcommand: $1" >&2; usage ;;
esac
}
case "${1:-}" in
enable|start|apply|reload) cmd_enable ;;
disable|stop) cmd_disable ;;
status) cmd_status ;;
check) cmd_check ;;
diff) cmd_diff ;;
edit) cmd_edit ;;
show) shift; cmd_show "$@" ;;
version) "$MATCHSTICK" version ;;
*) usage ;;
esac