iptables - Cible pour acheminer le paquet vers une interface spécifique?

25

Mon serveur domestique a deux interfaces principales, eth1(une connexion Internet standard) et tun0(un tunnel OpenVPN). Je voudrais utiliser iptablespour forcer tous les paquets générés par un processus local appartenant à l'UID 1002 à quitter tun0, et tous les autres paquets à quitter eth1.

Je peux facilement marquer les paquets correspondants:

iptables -A OUTPUT -m owner --uid-owner 1002 -j MARK --set-mark 11

Maintenant, je voudrais mettre une règle dans la chaîne POSTROUTING (probablement de la table mangle) pour faire correspondre les paquets marqués de 11 et les envoyer à tun0, suivie d'une règle qui correspond à tous les paquets et les envoyer à eth1.

J'ai trouvé la cible ROUTE, mais cela ne semble que réécrire l'interface source (sauf si je ne la lis pas correctement).

Iptables en est-il capable? Dois-je jouer avec la table de routage (via ip routeou simplement les routecommandes héritées ) à la place?

Edit: je pensais que je devrais peut-être fournir plus d'informations. Je n'ai pas d'autres règles iptables à l'heure actuelle (bien que je puisse créer des règles pour effectuer des tâches non liées à l'avenir). De plus, la sortie de ip routeest:

default via 192.168.1.254 dev eth1  metric 203
10.32.0.49 dev tun0  proto kernel  scope link  src 10.32.0.50
85.17.27.71 via 192.168.1.254 dev eth1
192.168.1.0/24 dev eth1  proto kernel  scope link  src 192.168.1.73  metric 203

Je n'ai pas touché à la table de routage - c'est comme ça à l'heure actuelle (même si elle a l'air assez sale). Je suis désolé, mais je n'ai pas routeinstallé la commande héritée sur cette machine.

Et la sortie de ip addr(bien sûr, eth0 et eth2 peut être ignorée - ce sont des cartes réseau qui ne sont pas utilisées actuellement):

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 1c:6f:65:2a:73:3f brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast     state UP qlen 1000
    link/ether 00:1b:21:9d:4e:bb brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.73/24 brd 192.168.1.255 scope global eth1
    inet6 fe80::21b:21ff:fe9d:4ebb/64 scope link
       valid_lft forever preferred_lft forever
4: eth2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 00:1b:21:6a:c0:4b brd ff:ff:ff:ff:ff:ff
5: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc     pfifo_fast state UNKNOWN qlen 100
    link/none
    inet 10.32.0.50 peer 10.32.0.49/32 scope global tun0

Edit: J'ai obtenu quelque chose qui fonctionne, mais il ne transfère pas les paquets marqués vers tun0. Fondamentalement, j'ai ajouté un tableau (11) et utilisé:

ip route add table 11 via 10.32.0.49 dev tun0
ip rule add priority 10000 fwmark 11 table 11

Quand je viens sudo -u user1000 wget -qO- whatismyip.org, j'obtiens l'adresse IP externe de mon domicile, mais si je le fais sudo -u user1002 wget -qO- whatismyip.org, j'obtiens également l'adresse IP de mon domicile (mais je devrais obtenir l'adresse IP à l'autre extrémité du tunnel OpenVPN).

L'exécution iptables -vLconfirme que les paquets sont mis en correspondance par la règle de marquage, mais ils ne semblent pas suivre la règle de routage.

EDIT: J'ai passé beaucoup de temps là-dessus, et bien que cela ne fonctionne toujours pas, je pense que je suis un peu plus proche.

La règle iptables doit être dans la manglechaîne OUTPUT de la table. Je pense que j'ai également besoin d'une règle MASQUERADE dans la natchaîne POSTROUTING de la table, pour définir l'adresse source. Cependant, le réacheminement qui se produit après le mangle de OUTPUT ne fonctionne pas correctement.

J'ai passé 5 heures là-dessus maintenant, donc je fais une pause et j'y reviendrai probablement plus tard ce soir ou demain.

Ethan
la source

Réponses:

26

J'ai récemment rencontré un problème similaire, quoique légèrement différent. Je voulais router uniquement le port TCP 25 (SMTP) sur une interface tap0 OpenVPN, tout en acheminant tout le reste du trafic (même pour le même hôte) sur l'interface par défaut.

Pour ce faire, j'ai dû marquer des paquets et définir des règles de traitement. Tout d'abord, ajoutez une règle qui rend les paquets de route du noyau marqués 2par une table traversante 3(expliqué plus loin):

ip rule add fwmark 2 table 3

Vous auriez pu ajouter un nom symbolique /etc/iproute2/rt_tables, mais je n'ai pas pris la peine de le faire. Le nombre 2et 3sont choisis au hasard. En fait, ceux-ci peuvent être les mêmes, mais pour plus de clarté, je ne l'ai pas fait dans cet exemple (bien que je le fasse dans ma propre configuration).

Ajoutez un itinéraire pour rediriger le trafic sur une autre interface, en supposant que la passerelle est 10.0.0.1:

ip route add default via 10.0.0.1 table 3

Très important! Videz votre cache de routage, sinon vous n'obtiendrez pas de réponse et restez assis les mains dans les cheveux pendant quelques heures:

ip route flush cache

Maintenant, définissez une règle de pare-feu pour marquer les paquets désignés:

iptables -t mangle -A OUTPUT -p tcp --dport 465 -j MARK --set-mark 2

La règle ci-dessus s'applique uniquement si les paquets proviennent de la machine locale. Voir http://inai.de/images/nf-packet-flow.png . Adaptez-le à vos besoins. Par exemple, si vous souhaitez uniquement acheminer le trafic HTTP sortant sur l' tap0interface, remplacez 465 par 80.

Pour empêcher les paquets envoyés d' tap0obtenir votre adresse LAN comme IP source, utilisez la règle suivante pour la changer en votre adresse d'interface (en supposant 10.0.0.2comme adresse IP pour l'interface tap0):

iptables -t nat -A POSTROUTING -o tap0 -j SNAT --to-source 10.0.0.2

Enfin, relâchez la validation de la source du chemin inverse. Certains vous suggèrent de le définir 0, mais 2semble un meilleur choix selon https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt . Si vous sautez ceci, vous recevrez des paquets (cela peut être confirmé en utilisant tcpdump -i tap0 -n), mais les paquets ne sont pas acceptés. La commande pour modifier le paramètre afin que les paquets soient acceptés:

sysctl -w net.ipv4.conf.tap0.rp_filter=2
Lekensteyn
la source
Pourquoi utilisez-vous SNAT au lieu de MASQUERADE? MASQUERADE ne fait-il pas la même chose, sauf que l'adresse IP est collectée à partir de l'interface lors de "l'exécution" et n'est pas codée en dur dans le fichier de configuration?
Ethan
6
@Ethan From man iptables: Il ne doit être utilisé qu'avec des connexions IP (commutées) attribuées dynamiquement: si vous avez une adresse IP statique, vous devez utiliser la cible SNAT. Le masquage équivaut à spécifier un mappage vers l'adresse IP de l'interface à laquelle le paquet sort, mais a également pour effet que les connexions sont oubliées lorsque l'interface tombe en panne. Vous avez raison, mais comme mon adresse IP ne changera jamais, j'ai décidé d'utiliser SNAT conformément aux recommandations de la page de manuel.
Lekensteyn
Je pense (bien que non testée) que la dernière étape (validation de la source du chemin inverse) ne soit pas nécessaire. Vous pouvez simplement ajouter une autre règle à la PREROUTINGchaîne à DNATl'adresse source correcte (selon votre passerelle par défaut).
Christian Wolf
7

J'ai résolu ça. Le problème était avec les règles de routage du tableau 11. Le tableau 11 était touché, mais les règles de routage le rendent inutilisable. Ce script est ce que j'utilise maintenant, et il semble bien fonctionner (bien qu'il soit évidemment spécifique à ma configuration). Aussi, j'ai créé un nouveau tableau 21 consacré à la liaison montante principale (eth1).

# Add relevant iptables entries.
iptables -t mangle -A OUTPUT -m owner --uid-owner 1002 -j MARK --set-mark 11
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE

# Flush ALL THE THINGS.
ip route flush table main
ip route flush table 11
ip route flush table 21
ip rule flush

# Restore the basic rules and add our own.
ip rule add lookup default priority 32767
ip rule add lookup main priority 32766
ip rule add fwmark 11 priority 1000 table 11
# This next rule basically sends all other traffic down eth1.
ip rule add priority 2000 table 21

# Restore the main table.  I flushed it because OpenVPN does weird things to it.
ip route add 127.0.0.0/8 via 127.0.0.1 dev lo
ip route add 192.168.1.0/24 dev eth1 src 192.168.1.73
ip route add default via 192.168.1.254

# Set up table 21.  This sends all traffic to eth1.
ip route add 192.168.1.0/24 dev eth1 table 21
ip route add default via 192.168.1.254 dev eth1 table 21

# Set up table 11.  I honestly don't know why 'default' won't work, or
# why the second line here is needed.  But it works this way.
ip route add 10.32.0.49/32 dev tun0 table 11
ip route add 10.32.0.1 via 10.32.0.50 dev tun0 table 11
ip route add 0.0.0.0/1 via 10.32.0.50 dev tun0 table 11

ip route flush cache

## MeanderingCode edit (parce que je ne peux pas encore commenter)

Merci pour cette réponse! Il semble que cela puisse devenir compliqué, car vous devrez conserver les informations sur l'itinéraire ici (peut-être en double ou en cassant d'autres choses qui pourraient vouloir définir des itinéraires).

Vous pouvez rencontrer des "choses étranges" dans votre table de routage depuis OpenVPN parce que le serveur est configuré pour "pousser" les routes, permettant à tout le trafic de passer via l'interface réseau VPN, plutôt que sur Internet "nu". Ou votre configuration OpenVPN ou tout script / application qui la configure définit des itinéraires.

Dans le premier cas, vous pouvez modifier votre configuration OpenVPN et mettre dans une ligne contenant « route-nopull »
Dans ce dernier, la configuration de contrôle pour OpenVPN ou tout emballage (network-manager-openvpn, par exemple sur de nombreuses distributions de bureau Linux en cours)
dans dans les deux cas, éliminer la configuration de routage où il est défini est plus propre et plus sûr que de vider la table, selon le moment où vous exécutez ce script et ce que fait votre système.

À votre santé!

Ethan
la source
2

Je pense que tu veux:

/sbin/ip route add default via 10.32.0.49 dev tun0 table 11
/sbin/ip rule add priority 10000 fwmark 11 table 11

http://lartc.org/howto/lartc.netfilter.html

Mais je n'ai pas testé ce qui précède.

mfarver
la source
La première commande renvoie "Erreur:" à "est en double ou" 10.32.0.49 "est une ordure."
Ethan
Désolé oublié le via entre le défaut et l'IP.
mfarver
Je l'ai essayé. Cela semble avoir le même effet que de laisser de côté le defaultmot - clé.
Ethan
Pour éliminer les options, vous pouvez essayer de faire une capture de paquets sur tun0 et voir si les paquets se retrouvent sur cette interface. tcpdump -i tun0 .. sinon, devez-vous le baser sur l'ID utilisateur? Pourriez-vous simplement le faire en fonction de l'adresse IP de destination (plus facile)? ajouter route <hôte distant> via 10.32.0.49
mfarver
Je ne peux pas me baser sur l'adresse IP de destination - il y en aurait beaucoup. Je pourrais aussi théoriquement le baser sur pid, mais c'est encore plus difficile, car je ne connais pas le pid jusqu'au démarrage du ou des démons.
Ethan
0

Cela peut être fait sans la commande iptables Exécuter une simple commande ip

Pour uid 1002:

ip rule add uidrange 1002-1002 table 502

Ajoutez la route par défaut pour la table 502 sur l'interface que vous voulez dire

eth0 ip rule add default via a.b.c.d dev eth0
jainendra
la source
J'ai testé cette commande, et cela n'a pas fonctionné:Error: argument "uidrange" is wrong: Failed to parse rule type
kasperd
@kasperd vous devez avoir mal agi, car cela fonctionne bien pour moi.
horseyguy