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 z vtnet0 do innego interfejsu w FreeBSD 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.

Częste problemy

Typowy błąd: reguły rdr są ustawione, ale ruch nie dociera do hosta docelowego. Dzieje się tak z dwóch powodów:

  1. 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.

  2. Brak SNAT – odpowiedź od hosta docelowego może nie wrócić przez serwer proxy.

Rozwiązanie krok po kroku

1. Definicja interfejsów

ext_if = "vtnet0"
wg_if  = "wgvps"

2. Reguły rdr (port redirection)

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.

3. Reguły nat (SNAT)

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

Pełny przykład konfiguracji

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

Jak testować przekierowanie

Użyj nc (netcat) do weryfikacji:

Na hoście docelowym (10.20.30.1)

Uruchom nasłuchiwanie na porcie:

nc -lu 51804

Z innego komputera

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).

Monitorowanie w czasie rzeczywistym

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'

Weryfikacja działania

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).

Podsumowanie

Dzię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.