nathelper
Dieser Artikel wurde für die folgenden Ubuntu-Versionen getestet:
Ubuntu 22.04 Jammy Jellyfish
Ubuntu 20.04 Focal Fossa
Du möchtest den Artikel für eine weitere Ubuntu-Version testen? Mitarbeit im Wiki ist immer willkommen! Dazu sind die Hinweise zum Testen von Artikeln zu beachten.
Artikel für fortgeschrittene Anwender
Dieser Artikel erfordert mehr Erfahrung im Umgang mit Linux und ist daher nur für fortgeschrittene Benutzer gedacht.
Zum Verständnis dieses Artikels sind folgende Seiten hilfreich:
Dieses Perl-Skript dient dazu, mit einem einzigen Kommandozeilenbefehl einen Ubuntu-Router mit der nötigen Network Address Translation (NAT) Funktionalität für IPv4 auszustatten, ohne dass man sich mit der iptables-Syntax beschäftigen muss. IPv6 wird im Skript nicht berücksichtigt.
Installation und Benutzung¶
Einfach das Skript irgendwo hin kopieren, wo es passt, bspw. nach /usr/local/sbin/nathelper. Dann die geeigneten Kommandozeilenargumente (s.u.) zusammenstellen und wenn alles wie gewünscht funktioniert den Befehl in einer Systemd-Unit konservieren.
Hinweis:
Beim Testen muss man dieses Skript natürlich als root bzw. mit sudo aufrufen, weil es selbst iptables benutzt.
Dieses Perl-Skript läuft natürlich nicht unter anderen Programmiersprachen, die z.B. wie "Perl 6" alias Raku zwar das Wort "Perl" im Namen führen, aber nicht Perl sind. Nur "Perl 5" ist echtes Perl und standardmäßig bei Ubuntu installiert.
Syntax¶
Das Skript wird komplett über seine Argumente gesteuert[1]:
nathelper -i IFACE OPTIONEN IP PORT(S)
Beispiele:
nathelper -i ppp+ -m # nur Masquerading nathelper -i ppp+ -m 192.168.6.5 80 21 192.168.6.6 6881-6889:7001-7009 # Masquerading und verschiedene Port-Weiterleitungen
In diesem Beispiel wird auf dem externen ppp-Device (ppp+
ist ein Joker-Ausdruck, der auf alle ppp-Devices zutrifft) Masquerading eingerichtet, sowie ein paar Ports nach innen weitergeleitet. Die Ports 80 und 21 werden an den Rechner 192.168.6.5 weitergeleitet und die Ports 6881 bis 6889 werden an die Ports 7001 bis 7009 des Rechners 192.168.6.6 weitergeleitet.
Optionen¶
-i iface
: Gibt die externe Netzwerkschnittstelle an. Für (DSL-)Modems sollte man einfachppp+
verwenden, ansonsten bspw.eth0
. Diese Option muss unbedingt angegeben werden.-m
: Diese Option gibt an, dass Masquerading verwendet werden soll. Dies ist in den allermeisten Fällen der Fall.-v
: Gibt jeden sysctl- und iptables-Befehl auf der Konsole aus, bevor er ausgeführt wird. So kann man nebenbei die iptables-Syntax lernen oder die Funktionsweise des Skriptes kontrollieren.-d
: Wie-v
, allerdings werden die Befehle nur ausgegeben, aber nicht tatsächlich ausgeführt.-q
: Am Ende des Skripts wird normalerweise eine Erfolgsmeldung ausgegeben. Mit Angabe der Option-q
unterbleibt dies.ip
: Wird ohne benannte Option auf der Kommandozeile angegeben. Bezeichnet die IP-Adresse eines Rechners, an den Port(s) weitergeleitet werden. Alle nachfolgenden port-Argumente bis zur nächsten IP beziehen sich auf diese Adresse.ports
: Ein Weiterleitungsstatement, dass sich immer auf die letzte vorhergehende IP-Adressenbezeichnung bezieht. Folgende Möglichkeiten gibt es:1234
→ Der Port 1234 wird 1:1 an denselben Port des Zielrechners weitergeleitet.1234-1238
→ Ein ganzer Abschnitt von Ports wird weitergeleitet.1234,1370
→ Mehrere verschiedene Ports werden weitergeleitet.1234:5678
→ Ein Port wird auf einen anderen Port des Zielrechners weitergeleitet.u1234
→ Dieses Port-Statement bezieht sich auf das UDP-Protokoll an Stelle des meist verwendeten TCP-Protokolls.
Die verschiedenen Operatoren können auch alle miteinander kombiniert werden, wobei aber auf eine gleiche Anzahl Ports rechts und links vom :
geachtet werden muss. Beispiel:
nathelper -i ppp+ -m 192.168.1.1 21-25,80,3128:10001-10007
Achtung!
Für jeden einzelnen Port wird eine iptables-Regel angelegt, was sich bei einer sehr hohen Anzahl an Regeln durchaus auf die Performance auswirken kann. Es ist deswegen nicht empfehlenswert, aus Bequemlichkeit bspw. mit 1-65535
alle Ports umzuleiten.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | #!/usr/bin/perl -w # # nathelper - Masquerading und Port-Forwarding in einer Kommandozeile # benoetigt natuerlich iptables # # Autor: otzenpunk (UbuntuUsers.de) # Lizenz: Public Domain use strict; use Getopt::Std; our %opts; usage() unless @ARGV; getopts('qvdhmi:', \%opts); usage() if $opts{'h'} or !$opts{'i'}; init(); # ip_forward, iptables -F masq($opts{'i'}) if ($opts{'m'}); # evtl. Masquerading our @forwards; our $fw_indx = 0; while ($_ = shift @ARGV) { # Array of Arrays: je 1xIP und n x Ports ++$fw_indx if /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ && @forwards; push @{$forwards[$fw_indx]}, $_; } forw($_) for @forwards; # jede IP verarbeiten print "NAT erfolgreich aktiviert.\n" unless $opts{'q'} or $opts{'d'}; exit(0); # masq(iface): Masquerading sub masq { my @iptables = (qw(/sbin/iptables -t nat -A POSTROUTING -o), $opts{'i'}, qw(-j MASQUERADE)); iptables(@iptables); } # forw(IP, Ports, ...): Ports duerfen Aufzaehlungen (zahl,zahl) # Ranges (zahl-zahl) # und Uebersetzungen (zahl:zahl) enthalten. sub forw { my $argptr = shift; # Pointer auf Array my $ip = shift @$argptr; # Erstes Element = IP for (@$argptr) { s/[^0-9u:,-]//ig; # saeubern von verbotenen Zeichen my $proto = s/^u//i ? 'udp' : 'tcp'; # u = UDP my ($von, $nach) = split ':'; # Uebersetzung trennen $nach ||= $von; # wenn kein ':' -> Ports bleiben gleich my @von = expand_range($von); # ',' und '-' expandieren my @nach = expand_range($nach); unless (@von == @nach) { # Falsche Parameter abfangen: print "Ungleiche Anzahl Ports: ", join(', ', @von), ' -> ', join(', ', @nach), "\n\n"; usage(); } my $i = 0; for (@von) { # je eine iptables-Zeile pro Port my @iptables = (qw(/sbin/iptables -t nat -A PREROUTING -i), $opts{'i'}, '-p', $proto, '--dport', $_, qw(-j DNAT --to-destination), "$ip:$nach[$i++]"); iptables(@iptables); } } } # iptables(Liste der Argumente, inkl. iptables-Pfad) sub iptables { # system() gibt >0 bei Fehler print join(' ', @_), "\n" if $opts{'v'} or $opts{'d'}; system(@_) && die("Fehler bei iptables. Root?\n") unless ($opts{'d'}); } # expand_range(Port-String inkl. [,-]) # ',' und '-' expandieren und Liste zurueck sub expand_range { my @werte = split ',', shift; @werte = map { my ($down, $up) = split '-', $_; $down < ($up ||= 0) ? ($down..$up) : $down; } @werte; return @werte; } sub init { print "sysctl -w net/ipv4/ip_forward=1\n" if $opts{'v'} or $opts{'d'}; system(qw(sysctl -w net/ipv4/ip_forward=1)) if not $opts{'d'}; iptables(qw(/sbin/iptables -t nat -F)); } sub usage { print <<EOT; Usage: $0 [-v] [-d] -i iface [-m] [ip ports ...] ... $0 [-h] -h : Hilfe -v : Verbose, iptables-Befehle ausgeben und durchfuehren -d : Debug, nicht wirklich durchfuehren -q : Keine Erfolgsmeldung ausgeben -i : externes Interface -m : Masquerading aktivieren ip ports : Ports, die auf IP umgeleitet werden, mehrere moeglich ports : 1234 -> Port wird 1:1 umgeleitet 1234:5678 -> Port wird auf anderen Port umgeleitet 1234-1238 -> Port-Range wird umgeleitet 1234-1238:5674-5678 -> beides u1234 -> UDP-Port(s) verwenden EOT exit(1); } |