Utiliser TUN / TAP avec Python

Aperçu

Une histoire sur l'utilisation de TUN / TAP, un pilote de réseau virtuel utilisé dans l'implémentation VPN, à partir de Python. Ce que j'ai vérifié lorsque j'ai créé https://github.com/kstm-su/dnsvpn.

Conditions préalables

--Mac ou Linux (Windows non vérifié) --Python (vérifié avec 3.5)

À propos de TUN / TAP

De Wikipedia

TAP simule un périphérique Ethernet et manipule la couche de liaison de données. TUN simule la couche réseau et manipule les paquets IP, etc. TAP est utilisé pour la génération de ponts et TUN est utilisé pour le routage.

Les paquets envoyés par le système d'exploitation à un appareil TUN / TAP sont envoyés au programme utilisateur connecté à cet appareil. Vous pouvez également envoyer des paquets de votre programme vers le périphérique TUN / TAP. Dans ce cas, le périphérique TUN / TAP transmet ces paquets à la pile de protocoles du système d'exploitation, il semble donc que les paquets aient été reçus de l'extérieur du côté du système d'exploitation.

Si vous souhaitez gérer à partir de L3 ou supérieur, utilisez TUN, et si vous souhaitez gérer à partir de L2, utilisez TAP.

Installation TUN / TAP

Mac Peut être installé avec une infusion.

$ brew cask install tuntap

Ce n'est pas grave s'il y a «tun [0-15]» et «tap [0-15]» sous «/ dev».

Linux Si le noyau est 2.2.x, 2.4.x ou supérieur, il doit être inclus en standard

$ lsmod | grep tun

Si rien ne sort, modprobe

$ sudo modprobe tun

Tout ce dont vous avez besoin est / dev / net / tun.

Enregistrer un appareil TUN / TAP

Rendre TUN / TAP visible avec ʻip link. En gros, vous ouvrez simplement le fichier de périphérique avec ʻopen, mais dans le cas de Linux, vous devez définir le nom du périphérique et le drapeau avec ʻioctl`, ce qui est un peu gênant. Lorsque le programme se termine, le périphérique n'est pas enregistré, de sorte que l'exemple de programme ne se termine pas par une boucle infinie.

Mac Ouvrez simplement / dev / tun * et c'est facile. (/ Dev / tap * lors de l'utilisation de TAP)

# tuntap-darwin.py
import os
import time
tun = os.open('/dev/tun0', os.O_RDWR)
while True:
    time.sleep(1)

Lorsque vous l'exécutez, vous pouvez voir que le nom de fichier du périphérique est reconnu comme le nom du périphérique réseau tel quel.

$ sudo python tuntap-darwin.py &
$ ip link show tun0
tun0: flags=8850<POINTOPOINT,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	open (pid 2251)

Linux Ouvrez / dev / net / tun et utilisez ʻioctlpour définir TUN ou TAP ou le nom du périphérique. Lorsque vous utilisez TAP, définissezTUN_TUN_DEV => TUN_TAP_DEV`.

# tuntap-linux.py
import os
import time
import fcntl

# https://github.com/kstm-su/dnsvpn/blob/master/lib/linux.py
import linux

tun = os.open('/dev/net/tun', os.O_RDWR)
ifr = linux.ifreq(name=b'hoge', flags=linux.IFF_NO_PI|linux.TUN_TUN_DEV)
fcntl.ioctl(tun, linux.TUNSETIFF, ifr)
while True:
    time.sleep(1)

Lorsque vous l'exécutez, vous pouvez voir qu'il reconnaît la chaîne de caractères passée à l'argument name de ʻifreq` comme nom de périphérique réseau.

$ sudo python tuntap-linux.py &
$ ip addr show hoge
6: hoge: <POINTOPOINT,MULTICAST,NOARP> mtu 1500 qdisc noop state DOWN qlen 500
    link/none

Communiquer avec TUN / TAP

Essayez d'envoyer et de recevoir des données à l'aide du périphérique TUN / TAP enregistré. Sur Mac et Linux, recevez simplement avec read et envoyez avec write. Cependant, si vous faites «lire» ou «écrire» tel quel, vous vous fâcherez, alors exécutez une commande externe pour vous connecter.

# tuntap.py
import os
import subprocess
tun = os.open('/dev/tun0', os.O_RDWR)
subprocess.check_call('sudo ifconfig tun0 192.168.100.2 192.168.100.1 netmask 255.255.255.0 up', shell=True)
while True:
    data = os.read(tun, 1500)
    print(data)
    os.write(tun, data)

Essayez de taper «ping» sur le périphérique réseau que vous avez créé

$ sudo python3 tuntap.py &
$ ping 192.168.100.1
PING 192.168.100.1 (192.168.100.1): 56 data bytes
b'E\x00\x00Tj\x15\x00\x00@\x01\xc7?\xc0\xa8d\x02\xc0\xa8d\x01\x08\x00t\xa4\x7f\x0e\x00\x00XA\xcbh\x00\x07\xf5\x98\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'
Request timeout for icmp_seq 0
b'E\x00\x00T~\xa2\x00\x00@\x01\xb2\xb2\xc0\xa8d\x02\xc0\xa8d\x01\x08\x00dk\x7f\x0e\x00\x01XA\xcbi\x00\x08\x05\xcf\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'
Request timeout for icmp_seq 1
b'E\x00\x00T\xa3\x8e\x00\x00@\x01\x8d\xc6\xc0\xa8d\x02\xc0\xa8d\x01\x08\x00b7\x7f\x0e\x00\x02XA\xcbj\x00\x08\x08\x01\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'
Request timeout for icmp_seq 2
b'E\x00\x00T2\x86\x00\x00@\x01\xfe\xce\xc0\xa8d\x02\xc0\xa8d\x01\x08\x00P\xf3\x7f\x0e\x00\x03XA\xcbk\x00\x08\x19C\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'

En regardant Wireshark, deux sont affichés pour chaque ping. C'est parce que le paquet reçu est envoyé tel quel. スクリーンショット 2016-12-03 4.32.29.png

Recommended Posts

Utiliser TUN / TAP avec Python
[Python] Utiliser JSON avec Python
Utiliser mecab avec Python 3
Utiliser DynamoDB avec Python
Utilisez Python 3.8 avec Anaconda
Utiliser python avec docker
Utiliser l'API Trello avec python
Utiliser l'API Twitter avec Python
Utiliser l'API subsonique avec python3
Python: comment utiliser async avec
Utiliser la caméra Point Grey avec Python (PyCapture2)
Utilisez vl53l0x avec RaspberryPi (python)
Utilisez NAIF SPICE TOOL KIT avec Python
Utiliser rospy avec virtualenv dans Python3
Utiliser Python mis en pyenv avec NeoVim
Utiliser la synthèse vocale Windows 10 avec Python
Utiliser OpenCV avec Python 3 dans Window
Utiliser PostgreSQL avec Lambda (Python + psycopg2)
FizzBuzz en Python3
Grattage avec Python
Statistiques avec python
Utilisez smbus avec python3 sous environnement pyenv
Utiliser DeepL avec python (pour la traduction d'articles)
Grattage avec Python
Python avec Go
Utiliser Amazon Simple Notification Service avec Python
Twilio avec Python
Intégrer avec Python
Jouez avec 2016-Python
[Introduction à Python] Utilisons foreach avec Python
Utilisez PIL ou Pillow avec Cygwin Python
AES256 avec python
Utiliser le chiffrement de la bibliothèque de chiffrement avec l'image Python de Docker
Testé avec Python
python commence par ()
avec syntaxe (Python)
Utiliser Application Insights avec Python 3 (y compris les bouteilles)
Bingo avec python
Zundokokiyoshi avec python
Utilisation des fonctions C ++ de python avec pybind11
Utilisez le pilote Web phantomjs de sélénium avec unittest de python
Jusqu'à ce que vous puissiez utiliser opencv avec python
Utiliser Python et MeCab avec Azure Functions
Excel avec Python
Micro-ordinateur avec Python
Cast avec python
Je veux utiliser MATLAB feval avec python
Utiliser des packages Python supplémentaires avec Serverless Framework (v1.x)
Spécifiez le fichier exécutable Python à utiliser avec virtualenv
Utilisez Logger avec Python pour le moment
Python> Exécuter avec des arguments d'exécution> Utiliser import argparse
Utiliser plusieurs versions de l'environnement python avec pyenv
Envelopper C avec Cython pour une utilisation à partir de Python
Le moyen le plus simple d'utiliser OpenCV avec python
Utilisez diverses fonctionnalités de rabbimq avec python pika
Je souhaite utiliser le répertoire temporaire avec Python2
Comment utiliser tkinter avec python dans pyenv
Utiliser Python dans un environnement Anaconda avec VS Code