shadowsocks/shadowsocks-rust · critical
open /dev/pf permission denied, consider restart with root u
Error message
open /dev/pf permission denied, consider restart with root user
What it means
On BSD systems the redirector's PacketFilter is opened lazily from /dev/pf; the PF static panics with this message when opening it fails with PermissionDenied. /dev/pf is root-only (or requires pf membership), so the redir service on BSD cannot work as an unprivileged user. This is a fail-fast guard rather than a recoverable error.
Source
Thrown at crates/shadowsocks-service/src/local/redir/sys/unix/bsd_pf.rs:373
Err(io::Error::other(format!(
"natlook UDP binding {}, {} not found",
bind_addr, peer_addr
)))
}
}
impl Drop for PacketFilter {
fn drop(&mut self) {
unsafe {
libc::close(self.fd);
}
}
}
pub static PF: LazyLock<PacketFilter> = LazyLock::new(|| match PacketFilter::open() {
Ok(pf) => pf,
Err(err) if err.kind() == ErrorKind::PermissionDenied => {
panic!("open /dev/pf permission denied, consider restart with root user");
}
Err(err) => {
panic!("open /dev/pf {err}");
}
});
View on GitHub (pinned to 8eb0f0a65b)
Solutions
- Restart the redir service as root (e.g. sudo or root-owned systemd unit)
- Grant the binary the needed capability/membership (add user to pf group or set uid bits)
- Run in a pf-enabled environment (host or jail with /dev/pf allowed)
- Verify /dev/pf exists (kldload pf / enable pf ruleset) if the device is absent
Defensive patterns
Strategy: validation
Validate before calling
# ensure /dev/pf is openable before launching the redir service: test -w /dev/pf || echo 'need root or pf group membership'
Prevention
- Run BSD redir services as root or with explicit pf access
- Pre-declare systemd capability/user requirements in the unit file
- Check pf module is loaded before service start
- Document the root requirement in deployment scripts
When it happens
Trigger: Lazily initializing `static PF: LazyLock<PacketFilter>` in bsd_pf.rs when a redir server on FreeBSD/OpenBSD/NetBSD calls into the PF NAT lookup and `PacketFilter::open()` returns an error whose kind is ErrorKind::PermissionDenied.
Common situations: Running shadowsocks-redir as a non-root user on BSD; starting via systemd without sufficient capabilities; /dev/pf restricted to group _pf or root; pf device not mounted in a jail/container.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- open /dev/pf {err}
- all plugins are exited. all connections may fail, check your
- {method} don't know how to generate nonce
- cannot get current working directory, {err:?}
- cannot get absolute path to working directory, {err:?}
AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09).
Data as JSON: /api/errors/2339855010254f17.
Report an issue: GitHub.