FreeBSD gateway: Webserver/SSH auf internem port von außen ansprechen geht nicht

Eisenfaust

Well-Known Member
Hallo.

Ich verwende FreeBSD 11-CURRENT, das Problem tritt aber auch unter FreeBSD 10-RC auf. Eingesetzt wird die OpenBSD pf des Systems, konfiguriert via /etc/pf.conf.

Szenario:

ich habe meinen DSL-Anbieter Router durch einen FreeBSD Server mit zwei Netzkarten ersetzt. Die Konfiguration ist (fast) klassisch:

LAN [PC1 ... PC6] <-->[int_if|wlan_if] FreeBSD [$ext_if] <--> Modem/WAN

FreeBSD ist mit zwei Netzkarten bestückt, wovon eine via PPPOE als tun0 mit dem Modem verbunden ist ($ext_if) und per DHCP eine IP meines Providers erhält. IP Forwarding ist selbstverständlich eingeschaltet (die Konfiguration ging unter einem frühen 10-CURRENT ohne Änderungen an der pf.conf problemlos!).

Das Interface $int_if ist die interne LAN Netzwerkkarte, ebenso $wlan_if (ein WiFi Adapter). Dahinter befinden sich dann eine Reihe anderer FreeBSD Maschinen/Klapprechner.

Auf dem Gateway/Router lauscht auf $int_if ein Apache Webserver sowie ein sshd. Jetzt zum Problem.

Ich würde gerne die Anfragen auf Port 80, 443 und 22 aus dem Netz via $ext_if (das ist bei mir tun0 wegen pppoe) auf das Interface $int_if und dort Port 80 umleiten und habe im Regelwerk pf.conf hierzu die Zeile

rdr on $ext_if proto tcp from any to ($ext_if) port https -> ($int_if) port https

erstellt.

Leider passiert überhaupt nichts, wenn ich von außen versuche, auf SSHD und HTTPD zuzugreifen. Mein sshd ist so konfiguriert, daß er auf der Adresse 192.168.0.1 lauscht (ListenAddress). Wenn ich die Standardeinstellung verwende, dann lauscht sshd auf allen Netwerkinterfaces - dann klappt auch der Kontakt von außen, weil auch auf der mit $ext_if (tun0) verknüpften IP Adresse gelauscht wird.

Die pf.conf Konfiguration ist relativ neu und stammt aus dem Netz, sie ist z. T. angefügt (den Kopf mit einigen IP Definitionen lasse ich weg).

Ich weiß leider nicht weiter. Vor allem irritiert mich, daß solange der rdr-Block (die Redirect Angaben unten, siehe das Beispiel oben) auskommentiert ist, ein pfctl -s state sowas wie dies hier liefert:

YYY.YYY.YYY.YYY:22 <- XXX.XXX.XXX:26731 PROXY:DST

YYYY ist die IP des $ext_if (tun0), die mir per DHCP zugewiesen worden ist, XXX ist die IP des Hosts, von dem ich per ssh auf den Server zugreifen möchte.

# $FreeBSD: src/etc/pf.conf,v 1.1.2.1 2004/09/17 18:27:14 mlaier Exp $
# $OpenBSD: pf.conf,v 1.21 2003/09/02 20:38:44 david Exp $
#
# See pf.conf(5) and /usr/share/examples/pf for syntax and examples.
# Required order: options, normalization, queueing, translation, filtering.
# Macros and tables may be defined and used anywhere.
# Note that translation rules are first match while filter rules are last match.

# Macros: define common values, so they can be referenced and changed easily.
int_if="em0"
ext_if="tun0"
wlan_if="wlan0"

# Log option
logopt="log"

# Ports open to internet
#ext_tcp_ports="{ ssh, domain, smtp, smtps, submission, imap, imaps, http, https, svn, postgresql, ntp }"
ext_tcp_ports="{ ssh, https, postgresql}"
ext_udp_ports="{ domain }"

# NATed ports
#nat_tcp_ports="{ ssh, submission, mail, http, https, smtp, smtps, imap, imaps, ldap, ldaps, ipp, >= 1024 }"
nat_tcp_ports="{ ssh, http, https, mail, submission, imap, imaps, >= 1024 }"
#nat_udp_ports="{ domain, syslog, >= 1024 }"
nat_udp_ports="{ domain }"

# External interface bandwidth
ext_bw="18Mb"

# High priority traffic server ports
high_ports="{ http, https }"

# Top priority traffic server ports (icmp traffic is already here)
top_ports="{ ssh, domain }"


# States.
mod_state="flags S/SA modulate state"
syn_state="flags S/SA synproxy state"

# Stateful Tracking Options.
# To clear <blocked_hosts> add to root's crontab:
# * * * * * /sbin/pfctl -t blocked_hosts -T expire 600 > /dev/null 2>&1
# This will block bad hosts for 10-11 minutes
sto_ext_ports="(max-src-conn-rate 500/10, overload <blocked_hosts> flush global)"
sto_nat_ports="(max-src-conn-rate 100/1)"

icmp_types = "echoreq"

table <abusers> persist file "/etc/pf.abusers"
table <net_wlan> persist { 192.168.2.0/24 }
table <net_local> persist { 192.168.0.0/24 }
table <net_trusted> persist { 192.168.0.0/24, 192.168.2.0/24 }
table <net_guest> persist { 192.168.254.0/24 }
table <net_me> { self }
table <blocked_nets> { 0.0.0.0/8, \
10.0.0.0/8, \
127.0.0.1/8, \
169.254.0.0/16, \
172.16.0.0/8, \
192.0.2.0/24, \
192.88.99.0/24, \
198.18.0.0/15, \
198.51.100.0/24, \
203.0.113.0/24, \
224.0.0.0/4, \
240.0.0.0/4 }

# Options: tune the behavior of pf, default values are given.
#set timeout { interval 10, frag 30 }
#set timeout { tcp.first 120, tcp.opening 30, tcp.established 86400 }
#set timeout { tcp.closing 900, tcp.finwait 45, tcp.closed 90 }
#set timeout { udp.first 60, udp.single 30, udp.multiple 60 }
#set timeout { icmp.first 20, icmp.error 10 }
#set timeout { other.first 60, other.single 30, other.multiple 60 }
#set timeout { adaptive.start 0, adaptive.end 0 }
#set limit { states 10000, frags 5000 }
set optimization normal
#set optimization aggressive
set block-policy drop
set require-order yes
set fingerprints "/etc/pf.os"
set state-policy floating
set debug urgent
set loginterface $ext_if
set skip on lo

# Normalization: reassemble fragments and resolve or reduce traffic ambiguities.
#scrub in all
#scrub out random-id fragment reassemble
#scrub all fragment reassemble no-df random-id reassemble tcp
scrub in all no-df min-ttl 100 max-mss 1440 fragment reassemble


# Queueing
#altq on $if_int bandwidth 16Mb cbq queue { default, samba, http, local, fun_in }
#altq on $if_int bandwidth 800Kb cbq queue { fun_out }
#queue default bandwidth 5% cbq(default)
#queue samba bandwidth 15%
#queue http bandwidth 10%
#queue local bandwidth 60%
#queue fun_in bandwidth 10%
#queue fun_out bandwidth 25%

##
## Hier beginnen nun unsere eigenen Regeln.
##

nat-anchor "ftp-proxy/*"
rdr-anchor "ftp-proxy/*"

nat on $ext_if from { $int_if:network, $wlan_if:network } to any -> ($ext_if)
#rdr on $int_if proto tcp from any to any port ftp -> 127.0.0.1 port 8021

rdr on $ext_if proto tcp from any to ($ext_if) port ssh -> ($int_if) port ssh
rdr on $ext_if proto tcp from any to ($ext_if) port https -> ($int_if) port https
rdr on $ext_if proto tcp from any to ($ext_if) port http -> ($int_if) port http
rdr on $ext_if proto tcp from any to ($ext_if) port postgresql -> ($int_if) port postgresql

### VORSICHT! ###
#pass in quick all
#pass out quick all

# Block invalid packets
block in $logopt quick from no-route
block in $logopt quick from urpf-failed

# Antispoofing rules
antispoof $logopt for $int_if
antispoof $logopt for $ext_if
antispoof $logopt for $wlan_if
antispoof $logopt for lo

# Incoming traffic on $ext_if
block drop in quick on { $ext_if } inet6 all
block drop in on $ext_if all

# Incoming traffic on $wlan_if
#block drop in quick on $wlan_if
#block drop in on $wlan_if

# toy with script kiddies scanning us
block in $logopt quick proto tcp flags FUP/WEUAPRSF
block in $logopt quick proto tcp flags WEUAPRSF/WEUAPRSF
block in $logopt quick proto tcp flags SRAFU/WEUAPRSF
block in $logopt quick proto tcp flags /WEUAPRSF
block in $logopt quick proto tcp flags SR/SR
block in $logopt quick proto tcp flags SF/SF

# FTP problemacy
anchor "ftp-proxy/*"
pass in quick on { $int_if, $wlan_if } inet proto tcp to port 21 divert-to 127.0.0.1 port 8021

# Allow ICMP pings and traffic to open ports
pass in on $ext_if inet proto icmp to ($ext_if) icmp-type 8 code 0 keep state
pass in on $ext_if proto tcp to ($ext_if) port $ext_tcp_ports $syn_state $sto_ext_ports
pass in on $ext_if proto udp to ($ext_if) port $ext_udp_ports keep state $sto_ext_ports

# Check src/dst of packets coming from outside
block in $logopt on $ext_if from <abusers>
block in $logopt on $ext_if from <ossec_fwtable>
block in $logopt on $ext_if from <blocked_hosts>
block in $logopt on $ext_if from <blocked_nets>
block in $logopt on $ext_if to 255.255.255.255
block in $logopt on $ext_if to !($ext_if)

# Outgoing traffic on $ext_if
pass out on $ext_if proto { tcp, udp } from ($ext_if) keep state
pass out on $ext_if inet proto icmp all keep state #queue top


# Incoming traffic
block return in on { $int_if, $wlan_if } all

# Pass packets sent to me on local interface
pass in on { $int_if, $wlan_if } from { <net_trusted> } to { <net_trusted>, <net_guest> } keep state
#pass in on $wlan_if from { <net_trusted> } to { ($wlan_if), ($int_if) } keep state

# Allow broadcasts on internal interface
pass in on { $int_if, $wlan_if } proto udp to 255.255.255.255 keep state

# Filter LAN ---> Inet traffic
pass in on { $int_if, $wlan_if } inet proto icmp from { <net_trusted>, <net_guest> } to any keep state
pass in on { $int_if, $wlan_if } proto tcp from { <net_trusted> } to any port $nat_tcp_ports $mod_state $sto_nat_ports
pass in on { $int_if, $wlan_if } proto udp from { <net_trusted> } to any port $nat_udp_ports keep state $sto_nat_ports

# Accept LAN ---> My external interface
pass in on { $int_if, $wlan_if } proto tcp from { <net_trusted>, <net_guest> } to ($ext_if) $mod_state $sto_nat_ports
pass in on { $int_if, $wlan_if } proto udp from { <net_trusted>, <net_guest> } to ($ext_if) keep state $sto_nat_ports


# Outgoing traffic on $int_if, $wlan_if
pass out on { $int_if, $wlan_if } all keep state
#
pass in on $wlan_if from { $wlan_if:network, $int_if:network } to ($wlan_if) keep state
 
Versuche es mal mit rdr pass oder erlaube http/ssh explizit in deinen Regeln für eingehenden Traffic.
Desweiteren würde ich es mal spaßeshalber mit den IP-Adressen versuchen:

rdr pass proto tcp from any to ($ext_if) port ssh -> <interne-ip-adresse> port ssh

Rob
 
Hallo rob.

Danke für Deine Antwort.

Dein Vorschlag funktioniert leider nicht - auch nicht mit der direkten Angabe der inbound IP Adresse.

Ich vermute, daß irgendetwas völlig falsch konfiguriert worden ist. Solange nämlich ein Service direkt auf dem "outbound" Interface lauscht ($ext_if), kann ich eine Verbindung zum Service herstellen. Das ist aber, meines erachtens, nicht Sinn des Anliegens. Ich will ja, daß alle Anfrage an die externe Adresse auf einen Server weitergeleitet werden.
 
Kannst du nochmal erklären, was du vor hast?

Du hast einen BSD-Router mit einem externen Interface und einem internen Interface.
Die Dienste sollen auf dem internen lauschen und du willst mittels Firewall auch externe Zugriffe erlauben?

Wenn ja, warum?

Wenn du eh alle Anfragen aus dem Netz umleitest, kannst du die Dienste auch auf die beiden Interfaces packen - beide Dienste unterstützen das.

Edit: Oder möchtest du die Anfragen auf einen bestimmten Server HINTER dem Router leiten - also quasi ein Portforwarding?
Gruß
Markus
 
Hallo.

ich will den Server nicht auf beiden IPs (insbesondere der outbound IP auf dem externen Netzinterface) horchen lassen, sondern möchte von diesem Interface die Anfrage auf eine zweite Adresse, der inbound Adresse, umleiten. sshd lauscht zum Beispiel in der Standardeinstellung auf allen Interfaces. mein httpd ist so konfiguriert, daß er nur auf 192.168.10.1 lauschen soll und ich will eben alle Anfragen von außerhalb, die über das externe Interface kommen, auf diesen Server weiterleiten. Im Grunde ein Port-Forwarding, ja.
 
Also hab ich das richtig verstanden.

Aber ich verstehe nicht warum?
Aus Sicherheitsgründen? Du hast im ersten Moment durch einfaches Weiterleiten keinerlei Vorteile, da die Pakete ja nur "durchgereicht" werden, daher die Frage.

Gruß
Markus
 
Hallo.

ich will den Server nicht auf beiden IPs (insbesondere der outbound IP auf dem externen Netzinterface) horchen lassen, sondern möchte von diesem Interface die Anfrage auf eine zweite Adresse, der inbound Adresse, umleiten. sshd lauscht zum Beispiel in der Standardeinstellung auf allen Interfaces. mein httpd ist so konfiguriert, daß er nur auf 192.168.10.1 lauschen soll und ich will eben alle Anfragen von außerhalb, die über das externe Interface kommen, auf diesen Server weiterleiten. Im Grunde ein Port-Forwarding, ja.

Was du machen willst, ist mittlerweile klar. Immernoch unklar ist, warum? Was soll das bringen?
 
@TCM:
Was du machen willst, ist mittlerweile klar. Immernoch unklar ist, warum? Was soll das bringen?

Warum? Ich möchte einfach, als Präludium zu mehr, eine extern gebundene Lauschstelle in meinem LAN und eine Möglichkeit, Anfragen gezielt an einen für die Anfrage vorgesehenen Server/Port delegieren. Betrachte es im Moment als rein akademisch. Geplant ist ein Selbstbau-Router mit ARM Chip, der gewisse Funktionen wie Routing und Firewalling übernehmen sollen wird, aber das sind noch unreife Projekte.

Nebenbei: sobald ich den Apache 2.4 auf *:80 oder *:443 lauschen lasse, bindet der natürlich auch auf die externe IP und die Zugriffe aus dem WAN funktionieren auch dann. Sobald ich aber in meine Regeltabelle "rdr" Regelsätze einpflege, die eine explizite Delegation erzwingen sollten, sind die Ports 80 und 443 von der Außenwelt abgeschnitten und nicht mehr erreichbar.
 
Du wiederholst ständig, was du machen willst. Du sagst nie, was es bringen soll, den Dienst intern zu binden und Anfragen von außen mit rdr reinzuleiten, anstatt den Dienst gleich auf *: zu binden.

ich will den Server nicht auf beiden IPs (insbesondere der outbound IP auf dem externen Netzinterface) horchen lassen, sondern möchte von diesem Interface die Anfrage auf eine zweite Adresse, [...blahblah...]

WARUM? Eine passende Antwort wäre z.B. "Weil ich noch ein 3. Interface habe, wo der Dienst nicht verfügbar sein soll" Also was ist es?
 
Kann ein Rechner überhaupt ein IP-Paket an sich selber schicken, ohne daß er dabei das Loopback-Interface nutzt?
Das "rdr" stellt die Pakete doch in die Ausgangsschlange des "int_if", dann müßte die Netzwerkkarte praktisch eine Verbindung zu sich selbst herstellen.
Eisenfaust, entweder Du läßt Deine Server auf dem Loopback-Interface lauschen oder Du plazierst im LAN einen Reflektor, d. h. einen Rechner, der einfach alle Pakete an den FreeBSD-Server zurückschickt, so daß sie dann in der Eingangsschlange des int_if landen.
 
Zurück
Oben