Comment faire en sorte que tout le trafic passe par une seule interface sous Linux

12

J'ai une interface auto-écrite tun0 ( basée sur TUN / TAP ) qui sort ce qu'elle reçoit.
J'ai besoin de tout le trafic du système pour passer par cette interface.
Le rôle de l'interface est:

  1. Comprendre les paquets susceptibles d'être censurés et les tunneler.
  2. Passez tout autre trafic intact.

Comme vous le devinez, j'essaie de construire un outil anti-censure.
La décision concernant le tunneling doit être prise à l'intérieur du processus tun0
car c'est uniquement là que nous pouvons utiliser un DNS de confiance.

J'ai besoin de votre aide pour me montrer comment faire circuler tout le trafic via une interface auto-écrite tun0. Si tun0 a besoin de changements, je vous demande de fournir de tels changements.

Voici comment j'ai essayé de faire passer tout le trafic via tun0 et a échoué (les pings échouent).

Compilation

  1. gcc tun0.c
  2. sudo ./a.out

Configuration

  1. sudo ip addr add 10.0.0.1/24 dev tun0
  2. créer la table John

    $ cat /etc/iproute2/rt_tables 
    #
    # reserved values
    #
    255     local
    254     main
    253     default
    0       unspec
    #
    # local
    #
    #1      inr.ruhep
    
    200 John
    

L'ordre est important:

  1. sudo ip rule add from all lookup John
  2. sudo ip route add default dev tun0 table John
  3. sudo ip rule add iif tun0 lookup main priority 500

    $ ip rule
    0:      from all lookup local 
    500:    from all iif tun0 lookup main 
    32765:  from all lookup John 
    32766:  from all lookup main 
    35000:  from all lookup default 
    

Dépannage

  1. sudo tcpdump -i wlp2s0 -qtln icmppuis ping -I tun0 8.8.8.8ne montre aucun paquet capturé, cela signifie qu'aucun paquet n'est transmis de tun0 à wlp2s0 via la iif tun0 lookup mainrègle.

  2. Quand je l' ai remplacé tun0avec lopartout il a travaillé pour moi.

Également essayé

  1. Désactivation du filtrage de chemin inverse, rp_filter=0dans/etc/sysctl.conf

Résolution des problèmes

iptables -I FORWARD -j LOG --log-prefix "filter/FORWARD " 
iptables -t nat -I OUTPUT -j LOG --log-prefix "nat/OUTPUT " 
iptables -t nat -I PREROUTING -j LOG --log-prefix "nat/PREROUTING " 
iptables -t nat -I POSTROUTING -j LOG --log-prefix "nat/POSTROUTNG "
tail -f /var/log/syslog

Des sources modifiées de réponse sont également ici .

ilyaigpetrov
la source

Réponses:

10

Ainsi, dans votre configuration, tous les paquets que vous essayez d'envoyer au réseau proviennent initialement de 10.0.0.1(car ils passent par l' tun0interface et son adresse locale est 10.0.0.1). Vous capturez les paquets, tout va bien jusqu'à présent.
Maintenant, tun0envoie les paquets plus loin. L'adresse source est 10.0.0.1et vous voulez que les paquets partent via une interface différente ( wlp2s0dans votre cas). C'est le routage, alors activons d'abord le routage:

sysctl -w net.ipv4.ip_forward=1

Après cela, si vous regardez tcpdumppour wlp2s0vous pouvez remarquer les paquets partent avec adresse source 10.0.0.1et non pas avec l'adresse source de l'interface wlan (ce que vous attendez , je suppose). Nous devons donc changer l'adresse source et cela s'appelle NAT source . Sous Linux, c'est facile avec l'aide de netfilter / iptables :

iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.0.1 -j MASQUERADE

Veuillez également vérifier que votre FORWARDchaîne a une ACCEPTpolitique ou vous devez autoriser le transfert avec quelque chose comme:

iptables -A FORWARD -i tun0 -o wlp2s0 -s 10.0.0.1 -j ACCEPT
iptables -A FORWARD -i wlp2s0 -o tun0 -d 10.0.0.1 -j ACCEPT

Tout devrait fonctionner maintenant: le noyau linux fait le routage, il déplace les paquets de l' tun0interface vers wlp2s0. netfilter devrait changer l'adresse IP source en l' adresse assignée 10.0.0.1à votre wlp2s0interface pour les paquets de sortie. Il mémorise toutes les connexions et lorsque les paquets de réponse reviennent (s'ils le sont), il change l'adresse de destination de l' wlp2s0adresse affectée à l' interface en 10.0.0.1(la fonction "conntrack").
Eh bien, cela devrait, mais ce n'est pas le cas. Il semble que netfilter soit confondu avec cette configuration de routage compliquée et le fait que le même paquet passe d'abord par la OUTPUTchaîne, puis est routé et arrive en PREROUTINGchaîne. Au moins sur Debian 8, cela ne fonctionne pas.
La meilleure façon de dépanner netfilter est la TRACEfonctionnalité:

modprobe ipt_LOG
iptables -t raw -A OUTPUT -p icmp -j TRACE
iptables -t raw -A PREROUTING -p icmp -j TRACE

J'active uniquement le traçage pour les paquets ICMP, vous pouvez utiliser un autre filtre pour déboguer.
Il montrera quelles tables et chaînes le paquet traverse. Et je peux voir que le paquet ne va pas plus loin dans la FORWARDchaîne (et qu'il n'est pas attrapé par la nat/POSTROUTINGchaîne qui le fait SNAT).
Vous trouverez ci-dessous plusieurs approches pour que cela fonctionne.

APPROCHE # 1

La meilleure façon de ne pas confondre netfilter est de changer l'adresse IP source des paquets dans l' tun0.capplication. C'est aussi le moyen le plus naturel. Nous devons changer 10.0.0.1 en 10.0.0.2 à l'aller et 10.0.0.2 à 10.0.0.1 au retour.
J'ai modifié tun0.cavec le code de changement d'adresse source. Voici le nouveau fichier et voici le fichier patch pour votre tun0.c. Les modifications apportées à l'en-tête IP impliquent également une correction de la somme de contrôle , j'ai donc pris du code du projet OpenVPN . Voici la liste complète des commandes que j'exécute après un redémarrage et un tun0_changeip.clancement propres :

ifconfig tun0 inet 10.0.0.1/30 up
sysctl -w net.ipv4.ip_forward=1
ip route add default dev tun0 table John
ip rule add from all lookup John
ip rule add from 10.0.0.2 lookup main priority 500
iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.0.2 -j MASQUERADE

Veuillez noter que vous n'avez pas besoin de désactiver le filtrage de chemin inverse dans ce cas, car tout est légal - tun0ne reçoit et n'envoie que les paquets qui appartiennent à son sous-réseau. Vous pouvez également faire un routage basé sur la source au lieu d'une interface.

APPROCHE # 2

Il est possible de le faire SNATavant que l' tun0interface atteigne le paquet . Ce n'est pas très correct cependant. Vous devrez certainement désactiver le filtrage de chemin inverse dans ce cas:

sysctl -w net.ipv4.conf.tun0.rp_filter=0
# It won't work without also changing the "all" value
sysctl -w net.ipv4.conf.all.rp_filter=0

Maintenant, faites SNAT: iptables -t nat -A POSTROUTING -o tun0 -s 10.0.0.1 -j SNAT --to-source ip.address.of.your.wlan.interface

Ici, nous changeons l'adresse source juste avant que les paquets n'atteignent l' tun0appareil. tun0.cle code renvoie ces paquets "tels quels" (avec l'adresse source modifiée) et ils sont correctement acheminés via l'interface WLAN. Mais vous pourriez avoir une IP dynamique sur l'interface wlan et vouloir utiliser MASQUERADE(afin de ne pas spécifier l'adresse d'interface explicitement). Voici comment vous pouvez utiliser MASQUERADE:

iptables -t nat -A POSTROUTING -o tun0 -s 10.0.0.1 -j SNAT --to-source 10.0.55.1
iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.55.1 -j MASQUERADE

Veuillez noter l' 10.0.55.1adresse IP " " - c'est différent. Vous pouvez utiliser n'importe quelle adresse IP ici, peu importe. Les paquets atteignent la nat/POSTROUTINGchaîne sur l' wlp2s0interface si nous changeons l'IP source avant. Et maintenant, il ne dépend pas d'une adresse IP statique pour l'interface WLAN.

APPROCHE # 3

Vous pouvez également utiliser fwmark. De cette façon , vous n'avez pas besoin SNATmais vous capturer des paquets sortants seulement:
nous devons d'abord désactiver chemin inverse filtrage pour , tun0car il transmet des paquets qui appartiennent à un autre réseau:

sysctl -w net.ipv4.conf.tun0.rp_filter=0
# It won't work without also changing the "all" value
sysctl -w net.ipv4.conf.all.rp_filter=0

Now let's alter the routing rules a bit:
# Delete old rules
ip rule del iif tun0 lookup main
ip rule del from all lookup John

# Packets will start going from wlan interface so they will have source address of it
iptables -t mangle -A OUTPUT -o wlp2s0 -j MARK --set-mark 1
ip rule add fwmark 0x1 lookup John

C'est un autre "hack" pour le routage et le netfilter qui fonctionne sur ma boîte Debian 8, mais je recommande quand même de prendre la première approche car elle est plus naturelle et n'utilise pas de hacks.


Vous pouvez également envisager de créer votre application en tant que proxy transparent . Je pense que ce serait beaucoup plus facile au lieu d'analyser les paquets du périphérique tun.

tifssoft
la source
Je devais utiliser -j SNAT, pas-s SNAT
ilyaigpetrov
Cela fonctionne mais les performances sont très intermittentes (il peut se bloquer pendant 10 secondes puis continuer à fonctionner). Je vais comprendre pourquoi cela se produit et comment y remédier.
ilyaigpetrov
1
Désolé c'était ma faute de frappe. J'ai ajouté une autre approche à ma réponse. N'ayez aucune idée du problème de performances. Au fait, pourquoi ne pas utiliser un proxy transparent avec iptables DNAT pour filtrer et détourner le trafic?
tifssoft
Je ne suis pas en mesure de reproduire votre approche de marque, je ne l'ai ajoutée qu'à sudo ip rule add iif tun0 lookup main priority 500elle, mais cela n'a toujours pas fonctionné. J'aime cette approche, dommage que je ne puisse pas la reproduire.
ilyaigpetrov
1
Merci pour votre nouvelle approche, je l'ai suivie pas à pas et cela a parfaitement fonctionné. Pourtant, je ne comprends pas pourquoi nous devons changer d'ips, surtout cela fonctionne. Si mes plans avec proxy TCP échouent, je pourrai revenir à votre réponse. Vous avez montré beaucoup de compétences en réseautage ici et je ne doute pas que vos compétences seront convoitées. Bonne chance!
ilyaigpetrov