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.
--Mac ou Linux (Windows non vérifié) --Python (vérifié avec 3.5)
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.
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
.
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éfinissez
TUN_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
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.
Recommended Posts