Skip to content

Commit 7e53443

Browse files
committed
Add FreeBSD CI workflow, rc.d startup script, and documentation
Add a GitHub Actions workflow that builds and tests sniproxy on the latest FreeBSD release. The workflow dynamically detects the newest FreeBSD version, builds with Capsicum support, runs the unit test suite, and verifies Capsicum capability mode is active on the mainloop process but not on the binder. Add an rc.d startup script (scripts/sniproxy.rc) for FreeBSD service management via rc.subr, supporting start/stop/reload. Update README.md with FreeBSD build and installation instructions, and update the man page with FreeBSD file paths and rc.d usage.
1 parent 57f2d3b commit 7e53443

File tree

5 files changed

+213
-2
lines changed

5 files changed

+213
-2
lines changed

.github/workflows/freebsd.yml

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
name: FreeBSD
2+
3+
on:
4+
push:
5+
branches: ["*"]
6+
pull_request:
7+
8+
jobs:
9+
detect-freebsd:
10+
name: Detect latest FreeBSD
11+
runs-on: ubuntu-latest
12+
outputs:
13+
version: ${{ steps.detect.outputs.version }}
14+
steps:
15+
- name: Detect latest FreeBSD release
16+
id: detect
17+
run: |
18+
set -euo pipefail
19+
# Fetch available FreeBSD VM images and find the latest stable release
20+
version=$(curl -sf https://download.freebsd.org/releases/VM-IMAGES/ |
21+
grep -oP '\d+\.\d+-RELEASE' |
22+
sort -t. -k1,1n -k2,2n |
23+
tail -1 |
24+
sed 's/-RELEASE//')
25+
if [ -z "$version" ]; then
26+
echo "Failed to detect FreeBSD version, using fallback" >&2
27+
version="14.2"
28+
fi
29+
echo "version=${version}" >> "$GITHUB_OUTPUT"
30+
echo "Detected FreeBSD ${version}"
31+
32+
build-freebsd:
33+
name: FreeBSD ${{ needs.detect-freebsd.outputs.version }}
34+
needs: detect-freebsd
35+
runs-on: ubuntu-latest
36+
timeout-minutes: 30
37+
steps:
38+
- name: Checkout
39+
uses: actions/checkout@v6
40+
41+
- name: Build and test on FreeBSD
42+
uses: cross-platform-actions/action@v0.25.0
43+
with:
44+
operating_system: freebsd
45+
version: "${{ needs.detect-freebsd.outputs.version }}"
46+
run: |
47+
set -eux
48+
49+
sudo pkg install -y \
50+
autoconf automake libtool pkgconf \
51+
libev pcre2 c-ares git
52+
53+
./autogen.sh
54+
./configure \
55+
LDFLAGS="-L/usr/local/lib" \
56+
CPPFLAGS="-I/usr/local/include"
57+
58+
# Verify Capsicum was detected
59+
grep -q 'HAVE_CAPSICUM 1' config.log
60+
61+
make -j$(sysctl -n hw.ncpu)
62+
63+
# Run unit tests
64+
make check || {
65+
echo "::warning::Some tests failed"
66+
cat tests/test-suite.log 2>/dev/null || true
67+
}
68+
69+
# Verify rc.d script is distributed
70+
test -f scripts/sniproxy.rc
71+
72+
# Smoke test: start sniproxy briefly with a test config
73+
printf '%s\n' \
74+
'user daemon' \
75+
'error_log { syslog daemon }' \
76+
'listener 127.0.0.1:18443 {' \
77+
' protocol tls' \
78+
' table hosts' \
79+
'}' \
80+
'table hosts {' \
81+
' .* 127.0.0.1:443' \
82+
'}' > /tmp/sniproxy-test.conf
83+
chmod 600 /tmp/sniproxy-test.conf
84+
85+
timeout 3 src/sniproxy -f -c /tmp/sniproxy-test.conf || test $? -eq 124
86+
87+
# Verify Capsicum is active: start as daemon and check
88+
src/sniproxy -c /tmp/sniproxy-test.conf
89+
sleep 1
90+
91+
# Check process flags for capability mode (0x100 bit)
92+
mainpid=$(ps ax -o pid,flags,args | grep 'sniproxy-mainloop' | grep -v grep | awk '{print $1}')
93+
binderpid=$(ps ax -o pid,flags,args | grep 'sniproxy-binder' | grep -v grep | awk '{print $1}')
94+
if [ -n "$mainpid" ]; then
95+
mainflags=$(ps -o flags= -p "$mainpid" | tr -d ' ')
96+
binderflags=$(ps -o flags= -p "$binderpid" | tr -d ' ')
97+
echo "mainloop flags=$mainflags binder flags=$binderflags"
98+
99+
# Mainloop must be in capability mode (flag 0x100 set)
100+
if [ $(( 0x$mainflags & 0x100 )) -eq 0 ]; then
101+
echo "::error::Main process is NOT in Capsicum capability mode"
102+
pkill sniproxy || true
103+
exit 1
104+
fi
105+
106+
# Binder must NOT be in capability mode
107+
if [ $(( 0x$binderflags & 0x100 )) -ne 0 ]; then
108+
echo "::error::Binder process should NOT be in capability mode"
109+
pkill sniproxy || true
110+
exit 1
111+
fi
112+
113+
echo "Capsicum verified: mainloop in cap mode, binder not"
114+
else
115+
echo "::error::sniproxy-mainloop process not found"
116+
pkill sniproxy || true
117+
exit 1
118+
fi
119+
pkill sniproxy || true

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,30 @@ This is the preferred installation method for modern Fedora based distributions.
219219

220220
sudo yum install ../sniproxy-<version>.<arch>.rpm
221221

222+
**Building on FreeBSD**
223+
224+
1. Install required packages
225+
226+
pkg install autoconf automake libtool pkgconf libev pcre2 c-ares
227+
228+
2. Build
229+
230+
./autogen.sh && ./configure LDFLAGS="-L/usr/local/lib" CPPFLAGS="-I/usr/local/include" && make
231+
232+
3. Install
233+
234+
sudo make install
235+
sudo cp scripts/sniproxy.rc /usr/local/etc/rc.d/sniproxy
236+
sudo cp /usr/local/etc/sniproxy.conf.sample /usr/local/etc/sniproxy.conf
237+
238+
4. Enable and start
239+
240+
sudo sysrc sniproxy_enable=YES
241+
sudo service sniproxy start
242+
243+
Capsicum capability mode is automatically enabled on FreeBSD when all
244+
listeners and backends use IP addresses (not Unix domain sockets).
245+
222246
***Building on OS X with Homebrew***
223247

224248
1. install dependencies.

man/sniproxy.8

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,22 @@ On Linux,
123123
\fBsniproxy\fR
124124
uses seccomp-bpf to restrict available system calls per process\&.
125125

126+
.SH FILES
127+
.TP
128+
.I /etc/sniproxy.conf
129+
Default configuration file (Linux)\&.
130+
.TP
131+
.I /usr/local/etc/sniproxy.conf
132+
Default configuration file (FreeBSD)\&.
133+
.TP
134+
.I /usr/local/etc/rc.d/sniproxy
135+
FreeBSD rc.d startup script\&.
136+
Enable with
137+
.B sysrc sniproxy_enable=YES
138+
and control with
139+
.B service sniproxy start|stop|reload\fR\&.
140+
126141
.SH "SEE ALSO"
127142
.PP
128-
\fBsniproxy.conf\fR(5)
143+
\fBsniproxy.conf\fR(5)\fR,
144+
\fBrc.subr\fR(8)

scripts/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
EXTRA_DIST = sniproxy.service
1+
EXTRA_DIST = sniproxy.service sniproxy.rc

scripts/sniproxy.rc

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!/bin/sh
2+
#
3+
# PROVIDE: sniproxy
4+
# REQUIRE: LOGIN DAEMON NETWORKING
5+
# KEYWORD: shutdown
6+
#
7+
# Add the following lines to /etc/rc.conf to enable sniproxy:
8+
#
9+
# sniproxy_enable (bool): Set to "YES" to enable sniproxy.
10+
# Default: "NO"
11+
# sniproxy_config (path): Path to sniproxy configuration file.
12+
# Default: "/usr/local/etc/sniproxy.conf"
13+
# sniproxy_flags (str): Extra flags passed to sniproxy.
14+
# Default: ""
15+
16+
. /etc/rc.subr
17+
18+
name="sniproxy"
19+
rcvar="${name}_enable"
20+
21+
load_rc_config $name
22+
23+
: ${sniproxy_enable:="NO"}
24+
: ${sniproxy_config:="/usr/local/etc/sniproxy.conf"}
25+
: ${sniproxy_flags:=""}
26+
27+
pidfile="/var/run/${name}.pid"
28+
command="/usr/local/sbin/${name}"
29+
command_args="-c ${sniproxy_config} ${sniproxy_flags}"
30+
required_files="${sniproxy_config}"
31+
32+
extra_commands="reload"
33+
reload_cmd="${name}_reload"
34+
start_precmd="${name}_prestart"
35+
36+
sniproxy_prestart()
37+
{
38+
if [ ! -f "${sniproxy_config}" ]; then
39+
err 1 "${sniproxy_config} not found"
40+
fi
41+
}
42+
43+
sniproxy_reload()
44+
{
45+
if [ -f "${pidfile}" ]; then
46+
kill -HUP $(cat "${pidfile}")
47+
else
48+
err 1 "${name} is not running"
49+
fi
50+
}
51+
52+
run_rc_command "$1"

0 commit comments

Comments
 (0)