Mit iptables nur bestimmte MAC-Adressen zulassen

Manche Dienste will man nur für bestimmte Geräte zugänglich machen. Befindet sich der Server und der Client im selben Layer 2 Netz, ist es einfach die Verbindungen nur für bestimmte MAC-Adressen zuzulassen. Kommt die Verbindung nicht von der konfigurierten MAC-Adresse, wird der Verbindungsaufbau nicht zugelassen und der Dienst ist für dieses Gerät somit nicht verfügbar.

Mein Anwendungsfall: Music Player Daemon (MPD)

Um Musik zu hören verwende ich den Music Player Daemon (MPD). Dieser kann man über eine einfache TCP Verbindung steuern (im Notfall auch mit telnet :)). Ich mag es auch die Musik von meinem Telefon aus mit einem speziellen Client zu steuern. Jedoch möchte ich nicht allen im Netzwerk Zugriff auf den MPD geben (Port 6600). Deshalb lasse ich nur Verbindungen von meinem Mobiltelefon zu, was ich über die MAC-Adresse des Telefons steuere.

Da ich das conntrack Modul verwende, ist eine bereits konfigurierte stateful Firewall eine Voraussetzung.

MAC-Adresse eintragen

Als erstes speichert man die MAC-Adresse in eine Variable, denn diese wird mehrmals verwendet:

PHONE="5C:0A:5B:93:3B:CB"

Logging

Die erste Regel wird für das Logging verwendet, damit ich im Systemlog sehe, wann sich mein Mobiltelefon verbunden hat. Pro Minute wird einmal geloggt und dann wird jeweils nur ein Eintrag geschrieben. Das LOG Target lässt das Paket weiter durch die Firewall laufen.

iptables -A INPUT -p tcp --dport 6600 -m conntrack --ctstate NEW \
  -m mac --mac-source $PHONE -m limit --limit 1/min --limit-burst 1 \
  -j LOG --log-prefix "Accept_MPD_IN" -m comment --comment "MPD_Phone"

Der MAC-Adresse den Zugriff erteilen

Bei der zweiten Firewallregel wird das Paket nur akzeptiert, falls die MAC-Adresse dem Telefon entspricht. Ansonsten gilt die Default-Regel der Firewall.

iptables -A INPUT -p tcp --dport 6600 -m conntrack --ctstate NEW \
  -m mac --mac-source $PHONE -j ACCEPT -m comment --comment "MPD_Phone"

Testen

So sehen die Einträge im Logfile aus, wenn man sich mit dem MPD verbinden will:

$ sudo journalctl -f
Mar 26 15:18:24 eris kernel: Accept_MPD_ININ=wlp2s0
OUT= MAC=58:94:6b:e9:fd:78:5C:0A:5B:93:3B:CB:08:00 SRC=152.96.234.131
DST=152.96.235.57 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=60908 DF PROTO=TCP
SPT=34662 DPT=6600 WINDOW=14600 RES=0x00 SYN URGP=0

Mar 26 15:22:23 eris kernel: DROP_ININ=wlp2s0
OUT= MAC=58:94:6b:e9:fd:78:5c:23:05:50:42:23:08:00 SRC=152.96.234.235
DST=152.96.235.57 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=16799 DF PROTO=TCP
SPT=47564 DPT=6600 WINDOW=14600 RES=0x00 SYN URGP=0 OPT
(020405B40402080A00E265920000000001030306)
...

Die erste Verbindung wurde zugelassen (Accept_MPD_IN) und die zweite wurde zurückgewiesen (Drop_IN).

IPv6

Dasselbe funktioniert mit IPv6:

PHONE="5C:0A:5B:93:3B:CB"
ip6tables -A INPUT -p tcp --dport 6600 -m conntrack --ctstate NEW \
  -m mac --mac-source $PHONE -m limit --limit 1/min --limit-burst 1 \
  -j LOG --log-prefix "Accept_MPD_IN" -m comment --comment "MPD_Phone"
ip6tables -A INPUT -p tcp --dport 6600 -m conntrack --ctstate NEW \
  -m mac --mac-source $PHONE -j ACCEPT -m comment --comment "MPD_Phone"

Fazit

Wie man sieht ist dieser Schutzmechanismus sehr schnell implementiert und nützlich, wenn man ein Service (der allenfalls keine Authentifizierung unterstützt) nur für ein bestimmtes Gerät zur Verfügung stellen will. Diese Dienste sind dann bei einem Portscan auch nicht sichtbar und man sieht den verweigerten Zugriff im Logfile.

Leave a Comment