So stellen Sie eine Schnittstelle mit dem Linux-tun-Treiber her

Lesezeit: 6 Minuten

Benutzer-Avatar
rmrobins

Es fällt mir schwer, dieses Problem herauszufinden – ich versuche, ein Programm zu schreiben, das mit dem Linux-Tunneltreiber interagiert. Auf einer sehr einfachen Ebene möchte ich einfach eine Anwendung erstellen, die Daten über einen Netzwerktunnel übertragen kann. Ich bin jedoch völlig ratlos, wie ich den Tunneltreiber richtig einrichten soll, um dies zu erreichen.

Ich entwickle auf Ubuntu 9.04 und habe das Tunneltreiber-Kernelmodul geladen.

Das Gerät existiert /dev/net/tunjedoch gibt es keine /dev/tunX Geräte. Ich kann diese Geräte nicht mit erstellen ifconfig – immer wenn ich laufe /sbin/ifconfig tun0 uperhalte ich beispielsweise die folgende Fehlermeldung:

tun0: FEHLER beim Abrufen von Schnittstellen-Flags: Kein solches Gerät.

Wenn ich versuche, mir das anzuschauen /dev/net/tun Gerät wird der folgende Fehler angezeigt:

cat: /dev/net/tun: Dateideskriptor in schlechtem Zustand.

Versuch zu öffnen /dev/tunX über ein kleines Programm, im Grunde ein einfaches

tun_fd = open( "/dev/tun0", O_RDWR )

gibt -1 zurück: Die Anwendung wird als Root ausgeführt und kann dieses Tunnelgerät immer noch nicht öffnen. Öffnen ist möglich /dev/net/tunjedoch scheint dies keine neue zu erzeugen /dev/tunX stattdessen zu verwendendes Gerät.

Zusammenfassend – wie schreibt man eine Anwendung, die den Linux-Tunneltreiber verwenden möchte? Irgendwelche Einblicke würden sehr geschätzt.

Vielen Dank; ~ Robert

Benutzer-Avatar
RubenLaguna

Es gibt keine /dev/tunX Gerätedateien. Stattdessen öffnen Sie die /dev/net/tun und konfigurieren Sie es über ioctl() deuten auf tun0. Um die prinzipielle Vorgehensweise zu zeigen, erstelle ich die TUN-Schnittstelle mit dem Kommandozeilentool ip tun tap und zeigen Sie dann den C-Code, der von diesem TUN-Gerät gelesen werden soll. So erstellen Sie die Tun-Schnittstelle über die Befehlszeile:

ip addr show # my eth0 inet address is 10.0.2.15/24 as Im running on a VirtualBox vm with Ubuntu 18.04 guest
sudo ip tuntap add mode tun dev tun0
sudo ip addr add 10.0.3.0/24 dev tun0  # give it an address (that does not conflict with existing IP)
sudo ip link set dev tun0 up  # bring the if up
ip route get 10.0.3.50  # check that packets to 10.0.3.x are going through tun0
# 10.0.3.50 dev tun0 src 10.0.3.0 uid 1000 
ping 10.0.3.50 # leave this running in another shell to be able to see the effect of the next example, nobody is responding to the ping

Das tun0 erstellt und alle Pakete an die Ziel-IP-Adresse 10.0.3.x werden weitergeleitet tun0.

Um Pakete von einem Userspace-Programm auf diese Schnittstelle zu lesen/schreiben, müssen Sie mit dem interagieren /dev/net/tun Gerätedatei mit ioctl(). Hier ist ein Beispiel, das die ankommenden Pakete liest tun0 Schnittstelle und drucken Sie die Größe:

#include <fcntl.h>  /* O_RDWR */
#include <string.h> /* memset(), memcpy() */
#include <stdio.h> /* perror(), printf(), fprintf() */
#include <stdlib.h> /* exit(), malloc(), free() */
#include <sys/ioctl.h> /* ioctl() */
#include <unistd.h> /* read(), close() */

/* includes for struct ifreq, etc */
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_tun.h>

int tun_open(char *devname)
{
  struct ifreq ifr;
  int fd, err;

  if ( (fd = open("/dev/net/tun", O_RDWR)) == -1 ) {
       perror("open /dev/net/tun");exit(1);
  }
  memset(&ifr, 0, sizeof(ifr));
  ifr.ifr_flags = IFF_TUN;
  strncpy(ifr.ifr_name, devname, IFNAMSIZ); // devname = "tun0" or "tun1", etc 

  /* ioctl will use ifr.if_name as the name of TUN 
   * interface to open: "tun0", etc. */
  if ( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) == -1 ) {
    perror("ioctl TUNSETIFF");close(fd);exit(1);
  }

  /* After the ioctl call the fd is "connected" to tun device specified
   * by devname ("tun0", "tun1", etc)*/

  return fd;
}


int main(int argc, char *argv[])
{
  int fd, nbytes;
  char buf[1600];

  fd = tun_open("tun0"); /* devname = ifr.if_name = "tun0" */
  printf("Device tun0 opened\n");
  while(1) {
    nbytes = read(fd, buf, sizeof(buf));
    printf("Read %d bytes from tun0\n", nbytes);
  }
  return 0;
}

Wenn Sie die haben ping 10.0.3.1 oder ping 10.0.3.40 Laufen, du wirst sehen Read 88 bytes from tun0 regelmäßig.

Sie können auch mit netcat UDP testen nc -u 10.0.3.3 2222 und Text eingeben + Enter.

Wenn nichts gedruckt wird, ist höchstwahrscheinlich die der tun0 zugewiesene ID-Adresse / der IP-Bereich nicht erreichbar/routbar/adressierbar. Stellen Sie sicher, dass die ip route get 10.0.3.4 zeigt an 10.0.3.4 dev tun0 Dies zeigt an, dass der Linux-Kernel weiß, dass Pakete an 10.0.3.4 an das tun0-Gerät gesendet werden sollten.

Zum Löschen der tun0 tun

sudo ip link set dev tun0 down
sudo ip tuntap del mode tun dev tun0

  • In dieser Antwort fehlt die Aussage: #include <unistd.h> für die Funktionen read() und close().

    – Benutzer3629249

    2. Dezember 2019 um 6:02 Uhr

  • Wenn ich Ihren C-Code ausführe, werden tatsächlich keine Pakete als Antwort auf das Ping der tun-Schnittstelle gelesen.

    – Petrus

    6. Januar um 14:39 Uhr

  • Ich habe es gerade ausprobiert und es funktioniert zumindest unter Ubuntu 18.04. @Peter Stellen Sie sicher, dass die IP-Adresse / der IP-Bereich, die Sie der tun0-Schnittstelle zugewiesen haben, sinnvoll und erreichbar/routbar ist (die IP, die ich im Beispiel verwendet habe, kann mit Ihrem IP-Plan in Konflikt stehen).

    – Ruben Laguna

    13. Januar um 15:18 Uhr


Benutzer-Avatar
vergänglich

Lesen /usr/src/linux/Documentation/networking/tuntap.rst.

Sie sollen open das /dev/net/tun Gerät. Eine Folge ioctl auf dem offenen fd wird das erstellt tun0 (oder wie auch immer Sie es nennen möchten) Netzwerkschnittstelle. Die Netzwerkschnittstellen von Linux entsprechen keiner /dev/* Gerät.

  • @rmrobins; was hast du getan, damit das wirklich funktioniert? Ich glaube, ich habe ein sehr ähnliches Problem wie Ihre ursprüngliche Frage. Ich habe das Gerät /dev/net/tun sichtbar, aber das Öffnen erzeugt keine Netzwerkschnittstelle. Ich habe versucht, die Beispiele br_select.c und br_sigio.c zu verwenden.

    – Simon

    16. November 2009 um 15:40 Uhr

  • Öffnen Sie, wie oben erwähnt, /dev/net/tun. Dann wird ein ioctl verwendet, um die eigentliche Schnittstelle selbst zu erstellen. Das ioctl heißt TUNSETIFF und das Argument ist vom Typ struct ifreq. Die Flags der ifreq-Struktur sollten auf IFF_TUN gesetzt werden. Sobald das ioctl zurückgekehrt ist, wird das ifr_name-Feld der ifreq-Struktur mit dem Namen der geöffneten Schnittstelle gesetzt. Hoffe das hilft!

    – rmrobins

    24. November 2009 um 6:45 Uhr

Ich bin auf ein nettes Einführungs-Tutorial dazu gestoßen

http://backreference.org/2010/03/26/tuntap-interface-tutorial/

Es wird mit einem Quell-Tarball geliefert.

Sie befand sich in denselben Google-Ergebnissen wie diese Frage. 🙂

eine andere Implementierung mit API fopen fclose fread in stdio.h in c11, statt api in unistd.h

#include <linux/if.h>
#include <linux/if_tun.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

FILE* tun_alloc(char *dev)
{
   struct ifreq ifr;
   FILE *fp;
   int err;

   // open in binary read+write mode
   if ((fp = fopen("/dev/net/tun", "r+b")) == 0)
   {
      perror("failed to open tun dev\n");
      exit(1);
   }

   memset(&ifr, 0, sizeof(ifr));

   /* Flags: IFF_TUN   - TUN device (no Ethernet headers)
    *        IFF_TAP   - TAP device
    *
    *        IFF_NO_PI - Do not provide packet information
    */
   ifr.ifr_flags = IFF_TUN;
   if (*dev)
      strncpy(ifr.ifr_name, dev, IFNAMSIZ);

   if ((err = ioctl(fileno(fp), TUNSETIFF, (void *)&ifr)) < 0)
   {
      fclose(fp);
      perror("failed to set mode!\n");
      exit(1);
   }
   strcpy(dev, ifr.ifr_name);
   return fp;
}

int main(void)
{
   char dev_name[IFNAMSIZ] = "tun0";
   char recv_buff[80];
   FILE* fp = tun_alloc(dev_name);

   // turn off buffering
   setbuf(fp, NULL); 

   while (1)
   {
      printf("reading from TUN device: %s\n", dev_name);
      size_t n = fread(recv_buff, sizeof(recv_buff[0]), sizeof(recv_buff), fp);
      printf("read bytes: %li\n", n);
   }
   return EXIT_SUCCESS;
}

1352390cookie-checkSo stellen Sie eine Schnittstelle mit dem Linux-tun-Treiber her

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy