Du bist hier:Start»CyanogenMod»Hacks»Internet-Zugang

Internetverbindung mit CyanogenMod

14.05.2015

mobile internet

Wenn ein Computer mit einem Netzwerk ohne Internetzugang verbunden ist, gibt es die Möglichkeit über eine zweite Netzwerkverbindung ins Internet zu gelangen. Eine zweite Netzwerkverbindung ist auch dann sinnvoll, wenn in einem vorhandenen Netzwerk nur ein eingeschränkter oder zensierter Internetzugang angeboten wird. Bisher war es eine übliche Variante über ein USB-Modem eine Internetverbindung einzurichten. Da heutzutage fast jede und jeder ein Smartphone hat, beschreibe ich in diesem Beitrag das Einrichten einer zweiten Internetverbindung unter Linux mit einem verbundenen Smartphone. Dabei wird an den Linux-Computer ein internetfähiges Smartphone mit dem Betriebssystem CyanogenMod über ein USB-Kabel angeschlossen.

Smartphone als Modem

Das folgende Bild stellt den Hardware-Aufbau dar:

mobile Internetverbindung übers Smartphone

mobile Internetverbindung übers Smartphone

Im oberen Beispiel ist der Linux-Computer über die Netzwerk-Schnittstelle eth0 mit einem Kabel an ein Netzwerk ohne Internetzugang angeschlossen. Das Smartphone und der Computer sind über ein USB-Kabel miteinander verbunden. In der Fachsprache nennt sich diese Art der Verbindung "USB tethering". Auf dem Computer mit Linux heißt die USB-Netzwerk-Schnittstelle usb0 und im Smartphone rndis0. Im Smartphone wird der Datenverkehr von rndis0 an die interne Schnittstelle rmnet0 weitergeleitet und gelangt über UMTS beziehungsweise LTE ins Internet.

Verwendete Schnittstellen

  • eth0: Kabel-gebundene Ethernet-Schnittstelle des Computers.
  • usb0: Netzwerkverbindung über USB auf der Seite des Computers. Verbindung des Computers zum Smartphone über ein USB-Kabel.
  • rndis0: Netzwerkverbindung über USB im Smartphone. RNDIS bedeutet Remote Network Driver Interface Specification.
  • rmnet0: RmNet ist eine proprietäre Schnittstelle im Smartphone, die vom Modem-Hersteller Qualcomm entwickelt wurde, um mit dem internen Modem zu kommunizieren. Über diese Schnittstelle wird die Mobilfunkverbindung hergestellt.

Die Nummer hinter dem Schnittstellennamen wird in Linux zum Durchnummerieren für mehreren Schnittstellen benutzt. Die erste Schnittstelle wird mit 0 beziffert - deshalb zum Beispiel eth0 für die erste Ethernet-Schnittstelle.

Zweite Internetverbindung unter Linux einrichten

Nach dem theoretischen kommt nun der praktische Teil. Zunächst muss auf dem Computer eine zweite Internetverbindung eingerichtet werden. Woher weiß jedoch der Computer, welche Pakete in das interne Netzwerk und welche Pakete über das mobile Internet geschickt werden sollen ? Die Lösung ist relativ einfach. In Linux können Netzwerkpakete in Abhängigkeit der Benutzerin beziehungsweise des Benutzers an die verschiedenen Netzwerkschnittstellen geleitet werden. In der Fachsprache nennt sich diese Art der Netzwerk-Weiterleitung "User based routing" oder "Owner based routing". Also muss für die zweite Netzwerkverbindung ein neuer Benutzer angelegt werden.

Neuen Benutzer unter Linux einrichten

Im folgenden Beispiel verwende ich den Benutzernamen "internet" mit der Benutzer-ID 1001. Falls diese ID bereits vergeben ist, dann sollte eine höhere Nummer verwendet werden. Alle folgenden Befehle müssen als Benutzer "root" ausgeführt werden.

# at the computer create a new user for the
# second internet connection with user id 1001:

sudo bash
adduser internet --uid 1001

# enter a password for the new user (twice) and press enter several times

# this should give you the directory /home/internet, if not then:
# mkdir /home/internet/
# chown -R internet:internet /home/internet/

Der Befehl "adduser internet" erstellt ein neues Home-Verzeichnis /home/internet/. Sollte das Verzeichnis nicht angelegt werden, dann muss das Home-Verzeichnis wie in den letzten beiden Befehlen beschrieben von Hand erstellt werden.

Die Auflösung von Namen in Internet-Adressen funktioniert in Linux über die Datei /etc/resolv.conf . In dieser Datei steht ein Nameserver, der einen Internetnamen wie zum Beispiel "heise.de" in die IP-Adresse 193.99.144.80 übersetzt. Diese Namensauflösung wird auch als Domain Name System - DNS - bezeichnet. Da unter Linux für das interne Netzwerk bereits ein Nameserver eingerichtet ist, muss für die zweite Internetverbindung eine zweite Datei /etc/resolv.conf mit einem anderen Nameserver erstellt werden. Mit dem Trick über eine change-root-Umgebung ist eine zweite resolv.conf-Datei unter /chroot/etc/resolv.conf kein Problem.

# create a second file system for the new user as a change root environment

mkdir /chroot
cp -a /etc /chroot/etc

# remove in case the file is a link
rm -f /chroot/etc/resolv.conf

# create a new DNS entry for the second internet connection
echo "nameserver 85.214.20.141" > /chroot/etc/resolv.conf

Da der Benutzer "internet" nicht nur mit dem Verzeichnis /etc auskommt, müssen die anderen Verzeichnisse für diesen Benutzer als zweites Dateisystem in die change-root-Umgebung eingehangen werden. Das funktioniert mit dem Befehl "mount --bind". Die definierten Verzeichnisse können bei verschiedenen Linux-Distributionen leicht abweichen.

# define the directories for the second file system
CHROOT_DIRECTORIES="bin boot dev dev/pts home lib lib32 lib64 media opt proc root run run/lock run/shm sbin selinux srv sys tmp usr var"
REVERSED_DIRECTORIES=$(echo $CHROOT_DIRECTORIES | awk '{ for (i=NF; i>1; i--) printf("%s ",$i); print $1; }')

# if you do not want to unmount: REVERSED_DIRECTORIES=""

# check if the second file system is already mounted
mount | grep -q /chroot
if [ $? -eq 0 ];then
  echo "already mounted - going to unmount"
  for directory in $REVERSED_DIRECTORIES; do
    umount /chroot/$directory
  done
else
  for directory in $CHROOT_DIRECTORIES; do
    mkdir /chroot/$directory 2> /dev/null
    mount --bind /$directory /chroot/$directory
  done
fi

Jetzt kann der Benutzer "internet" in das neu erstellte Dateisystem wechseln:

# enable graphical user interface for the user "internet"
xhost +SI:localuser:internet

# change into the chroot environment
chroot /chroot/ /bin/su - internet

Durch das Eintragen von chroot in die Datei /etc/sudoers kann eine Benutzerin oder ein Benutzer auch ohne root-Rechte zum Benutzer "internet" wechseln. Im folgenden Beispiel benutze ich den Benutzer mit dem schönen Namen "user".

# prepare sudo for chroot:
vi /etc/sudoers

# add the following line with your user name
# at the end of /etc/sudoers:
user ALL=(root) NOPASSWD:/usr/sbin/chroot

# as unprivileged user:
xhost +SI:localuser:internet
sudo chroot /chroot/ /bin/su - internet

Internetverbindung mit CyanogenMod konfigurieren

Auf dem Smartphone sollte jetzt der Flugmodus aus- und die "mobilen Daten" eingeschaltet werden - also die Internetverbindung über Mobilfunk. In CyanogenMod muss die Android Debug Bridge (adb) freigeschaltet sein (siehe Entwickleroptionen). Wenn das Smartphone und der Computer über ein USB-Kabel das erste Mal miteinander verbunden sind und adb gestartet wird, dann muss auf dem Smartphone beim Bestätigungsdialog "OK" getippt werden. Über die Android Debug Bridge wird anschließend USB tethering eingeschaltet und das Smartphone konfiguriert.

# run the android debug bridge with root privileges

# first download android debug bridge (adb) if it does not exist
if [ ! -e /usr/bin/adb ]; then
  # download android debug bridge
  # you might need the 32-bit libraries
  # sudo apt-get install ia32-libs
  wget http://dl.google.com/android/repository/platform-tools_r19.0.1-linux.zip

  # extract the zip that contains adb
  unzip platform-tools_r19.0.1-linux.zip
  cp platform-tools/adb /usr/bin/
fi

# make sure your smartphone is connected via USB and adb is enabled

adb kill-server
adb root
# if you do this the first time
# look at the confirmation dialogue

adb wait-for-device

# enable USB tethering with adb
adb shell "setprop sys.usb.config rndis,adb"

adb wait-for-device
adb devices

echo "configure IP address on the smartphone"
adb shell "ifconfig rndis0 192.168.42.129 up"

result=$(adb shell "iptables -nvL | grep rndis | wc -l | tr -d '\n'")
if [ "$result" == "0" ];then
  adb shell "iptables -I INPUT -i rndis0 -j ACCEPT"
  adb shell "iptables -I OUTPUT -o rndis0 -j ACCEPT"
fi

# enable packet forwarding in cyanogenmod
adb shell "echo 1 > /proc/sys/net/ipv4/ip_forward"
adb shell "iptables -I natctrl_FORWARD -j ACCEPT"
adb shell "iptables -t nat -I POSTROUTING -j MASQUERADE"

echo "configure IP address on computer"
ifconfig usb0 192.168.42.1 up

# check the connection with a ping
ping -c 1 -W 2 192.168.42.129

# should display:
# 1 packets transmitted, 1 received, 0% packet loss, time 0ms

# if ping does not work check the interfaces:
# ifconfig usb0
# adb shell busybox ifconfig rndis0

# if the firewall is a problem, type:
# iptables -I INPUT -i usb0 -j ACCEPT
# iptables -I OUTPUT -o usb0 -j ACCEPT

Auch wenn es auf dem Smartphone nicht stört, sollten später vor dem Entfernen des Smartphones die eingerichteten iptables-Regeln zurückgesetzt werden:

# revert the iptables rules before you remove the smartphone

adb shell "iptables -D natctrl_FORWARD -j ACCEPT"
adb shell "iptables -t nat -D POSTROUTING -j MASQUERADE"
adb shell "echo 0 > /proc/sys/net/ipv4/ip_forward"

Routing für die zweite Netzwerkverbindung einrichten

Auf dem Computer muss jetzt noch die Weiterleitung der Datenpakete an die zweite Netzwerkverbindung für den Benutzer "internet" eingerichtet werden. Das funktioniert mit der Firewall iptables und der Benutzer-ID 1001 des Benutzers "internet". Dabei werden alle Datenpakete des Benutzers mit einer Nummer markiert - in diesem Beispiel die Nummer 10 beziehungsweise hexadezimal 0xa. Damit die manuellen Netzwerkeinstellungen nicht von einem automatischen Programm wie dem NetworkManager unter Ubuntu überschrieben oder gelöscht werden, sollte der NetworkManager vorher ausgeschaltet werden:

# at the computer as user root:

# disable the NetworkManager
service network-manager stop

# if this disables your eth0 interface then type:
# dhclient eth0

# set up a second routing table for usb0
grep -q usb0 /etc/iproute2/rt_tables
if [ $? -ne 0 ];then
  echo -e "10\tusb0" >> /etc/iproute2/rt_tables
fi

# add a mark to the packets based on the
# user / owner of the sending process
iptables -t mangle -I OUTPUT -m owner --uid-owner 1001 -j MARK --set-xmark 0xa

# create the table rule for marked packets
ip rule show | grep -q 0xa
if [ $? -eq 1 ];then
  ip rule add from all fwmark 0xa pri 100 table usb0
fi

# clear table before writing to it
ip route flush table usb0

# create a routing table with default gateway usb0
ip route show table main | grep -Ev ^default | while read ROUTE ; do
  ip route add table usb0 $ROUTE
done

ip route add table usb0 default via 192.168.42.129

# now disable source checking rp_filter
for rp_filter in $(ls -1 /proc/sys/net/ipv4/conf/*/rp_filter);do echo 0 > $rp_filter;done

# enable packet forwarding at the computer
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -I POSTROUTING -j MASQUERADE

Die eingerichteten Routing-Regeln leiten den Netzwerkverkehr des Benutzers "internet" an die Netzwerkschnittstelle usb0 weiter. Über das USB-Kabel kommen die Pakete bei der Schnittstelle rndis0 des Smartphones an und werden durch die Forwarding-Regeln an rmnet0 weitergeleitet. Eine "main routing Tabelle" beziehungsweise "default routing table" ist immer auf dem Computer notwendig, sonst funktioniert das Routing für die zweite Internetverbindung nicht. Wenn alles richtig konfiguriert ist, dann sollte nslookup und das Abfragen der IP-Adresse auf dem Computer mit dem Benutzer "internet" funktionieren. Um den Firefox-Browser des Benutzers "internet" vom bisherigen Firefox zu unterscheiden, kann die Farbe der Navigationsleiste geändert werden:

# nslookup should work now for user "internet":
nslookup heise.de

# query the mobile IP address
wget -qO- http://torsten-traenkner.de/web/ipaddress.php; echo

# or with curl if installed:
curl http://torsten-traenkner.de/web/ipaddress.php; echo

# start firefox as user "internet":
firefox &

# go to the firefox profile directory
cd ~/.mozilla/firefox/*default/

# create a directory chrome
mkdir chrome

# create the file userChrome.css
# with a different color of the navigation bar
echo "#nav-bar { background-color: #a0a0a0 !important }" >> chrome/userChrome.css

Trouble-Shooting

Da das Einrichten der Routing-Regeln nicht ganz trivial ist, gibt es hier einige Tipps zum Debuggen von Problemen:

# debug as user root with:
ip rule show
# should display something like:
# 100: from all fwmark 0xa lookup usb0

route -n

# display the routing table for interface usb0
ip route show table usb0
# should display something like:
# default via 192.168.42.129 dev usb0

# display the firewall rules:
iptables -nvL
iptables -nvL -t nat
iptables -nvL -t mangle

# should display something like:
# Chain OUTPUT (policy ACCEPT 1872 packets, 1240K bytes)
#  pkts bytes target     prot opt in     out     source               destination        
#     2    90 MARK       all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 1001 MARK set 0xa

# nslookup should work for user "internet":
nslookup heise.de

# debug with tcpdump at the computer:
tcpdump -i usb0 -enX -s 0

# debug with tcpdump at the smartphone:
tcpdump -i rndis0 -enX -s 0

Das ultimative Werkzeug um Netzwerk-Probleme zu untersuchen ist und bleibt tcpdump. In Linux läßt sich tcpdump problemlos über die Paketquellen installieren. Für CyanogenMod gibt es tcpdump im Debian-Kit. Außerdem hilft auch ein Blick auf die Anzahl der Daten-Pakete bei den Iptables-Regeln, um herauszufinden wo die Pakete eventuell verenden.

Automatisierung

Die ganzen Befehle müssen natürlich nicht jedes Mal von Hand eingegeben werden. Über den Userspace device daemon (udevd) lassen sich die Befehle automatisieren. Dazu müssen die oben beschriebenen Befehle in einem Shell-Skript gespeichert werden, so dass udevd dieses Skript automatisch beim Einstecken des Smartphones ausführen kann.

Alternative Hardware-Kombinationen

Die oben beschriebenen Kommandozeilen gelten natürlich auch für andere Hardware-Kombinationen. So kann zum Beispiel bei Benutzung des Point-to-Point-Protokolls anstelle der Schnittstelle usb0 auch ppp0 in die oberen Kommandos eingetragen werden.

Falls noch etwas unklar sein sollte, dann kannst du die Kommentar-Funktion benutzen.

Kommentar schreiben