Przekierowanie portów FreeBSD PF
12 sierpnia 2026 blog freebsd firewall pf
Jak we FreeBSD przekierować porty z jednego do innego interfejsu używając PF?
Przekierowanie portów FreeBSD PF
12 sierpnia 2026 blog freebsd firewall pf
Jak we FreeBSD przekierować porty z jednego do innego interfejsu używając PF?
Jak skonfigurować przekierowanie portów w firewallu PF na FreeBSD, gdy masz serwer z dwoma interfejsami: głównym (vtnet0) oraz WireGuard (wgvps), i chcesz kierować ruch z sieci zewnętrznej do hosta wewnątrz tunelu WireGuard.
vtnet0 – interfejs publiczny (external)wgvps – interfejs WireGuard z IP 10.20.30.210.20.30.1vtnet0 na 10.20.30.1Typowy błąd: reguły rdr są ustawione, ale ruch nie dociera do hosta docelowego. Dzieje się tak z dwóch powodów:
Brak pasującej reguły pass – po rdr adres zmienia się na wewnętrzny, więc reguła pass in on $ext_if ... to ($ext_if) nie pasuje.
Brak SNAT – odpowiedź od hosta docelowego może nie wrócić przez serwer proxy.
ext_if = "vtnet0"
wg_if = "wgvps"
Przekierowanie pojedynczych portów:
rdr pass on $ext_if inet proto udp from any to ($ext_if) port 51805 -> 10.20.30.1 port 51804
rdr pass on $ext_if inet proto udp from any to ($ext_if) port 51806 -> 10.20.30.1 port 51806
Zakres portów:
rdr pass on $ext_if inet proto udp from any to ($ext_if) port 51820:51840 -> 10.20.30.1 port 51820:51840
Użycie rdr pass oznacza, że "ruch po przekierowaniu jest automatycznie dozwolony, pomijając normalne reguły filtrujące". Jest to tzw. "shortcut rule" - unika konieczności tworzenia drugiej reguły.
Konieczne, aby odpowiedzi od hosta docelowego wróciły przez nasz serwer:
nat on $wg_if proto udp from any to 10.20.30.1 port { 51804, 51806 } -> 10.20.30.2
nat on $wg_if proto udp from any to 10.20.30.1 port 51820:51840 -> 10.20.30.2
Można też scalić w jedną regułę:
nat on $wg_if proto udp from any to 10.20.30.1 port { 51804, 51806, 51820:51840 } -> 10.20.30.2
ext_if = "vtnet0"
wg_if = "wgvps"
set block-policy return
set skip on lo
scrub in on $ext_if all fragment reassemble
# Przekierowania
rdr pass on $ext_if inet proto udp from any to ($ext_if) port 51805 -> 10.20.30.1 port 51804
rdr pass on $ext_if inet proto udp from any to ($ext_if) port 51806 -> 10.20.30.1 port 51806
rdr pass on $ext_if inet proto udp from any to ($ext_if) port 51820:51840 -> 10.20.30.1 port 51820:51840
# SNAT dla ruchu przekierowanego
nat on $wg_if proto udp from any to 10.20.30.1 port { 51804, 51806, 51820:51840 } -> 10.20.30.2
# Blocking default
block in all
# Allow
pass out quick
# apply changes: sudo pfctl -nvf /etc/pf.conf && sudo pfctl -f /etc/pf.conf
Użyj nc (netcat) do weryfikacji:
Uruchom nasłuchiwanie na porcie:
nc -lu 51804
Wyślij dane do publicznego IP serwera:
echo "test message" | nc -u YOUR_PUBLIC_IP 51805
Powinno pojawić się na hoście docelowym (10.20.30.1).
Na serwerze z PF:
# Logi z pflog0
tcpdump -n -e -ttt -i pflog0
# Statystyki reguł PF
pfctl -sn -vv
# Szczegóły konkretnych reguł
pfctl -sr -vv | grep -E 'rdr|nat'
Sprawdź liczniki pakietów przy każdej regule:
pfctl -sn -vv | grep "10.20.30.1"
Jeśli licznik Packets przy regule rdr rośnie, ale przy nat nie - pakiet ginie między przekierowaniem a filtrowaniem. Jeśli oba rosną, a ruch nie dociera - sprawdź routing na 10.20.30.1 (brama domyślna powinna wskazywać na 10.20.30.2).
rdr pass lub dodaj pass in to 10.20.30.1nat on $wg_if ... to 10.20.30.1 -> 10.20.30.2nc -lu na docelowym + nc -u z klientatcpdump -i pflog0 + pfctl -sn -vvDzięki tej konfiguracji możesz bezpiecznie i skutecznie przekierowywać ruch z interfejsu zewnętrznego do hostów ukrytych w tunelu WireGuard, wykorzystując pełną kontrolę oferowaną przez PF na FreeBSD.