Cette fiche opérationnelle décrit la mise en place d'adresses IPv6 supplémentaires sous Linux / Debian / Raspbian.
IPv6 présente au moins deux avantages sur IPv4 :
NAT
.
Une IPv6 est codée sur 128 bits découpés conventionnellement en huit plages de 16 bits présentées sous en 8 groupes de 4 chiffres hexadécimaux 0–9a–F
séparés par ':'
tel fe80:3e0a:001a:0000:0000:0000:2215:02c3
fe80:3e0a:1a:0:0:0:2215:2c3
;
'::'
. Nous obtenons ainsi l'écriture canonique fe80:3e0a:1a::2215:12c3
;
:port
, ainsi dans la barre d'adresse URL d'un navigateur [fe80:3e0a:1a::2215:12c3]:80
Une adresse locale (lien/link) non routable débute par fe80
, comme celle illustrée ici.
Les adresses IPv4 sont codées sur 32 bits ; leur 4 myards de possibilités comptent pour zéro par rapport aux 128 millards de milliards de milliards de myards de choix en IPv6.
Les 64 premiers bits (les 4 premiers groupes) sont presque toujours utilisés par les réseaux publics connectés sur l'internet. N'importe quel routeur d'hébergeur et n'importe quelle box internet laissent donc les 64 derniers bits disponibles pour adresser directement et publiquement une quasi infinité de machines ou d'objets sur le réseau local, d'un PC à une brosse à dent « connectée » voir à chaque poil d'icelle.
Plus besoin des contorsions nécessaires en IPv4 pour contourner la limitation du nombre d'adresses où, derrière un routeur ou une box, on trouve des adresses privées en 192.168.x.y
ou en 10.a.b.c
non routables sur l'internet. Oublions donc le NAT
, la translation d'adresse et les conflits sur un même port avec deux serveurs derrière : en IPv6 on peut déjà au moins attribuer deux adresses publiques (externes) distinctes !
Typiquement sur une machine on aura
ip -6 addr list # or shorter: ip -6 aoù :1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000 inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000 inet6 2a01:e7a:1d2:e030:2a84:7d:2b15:40eb/64 scope global mngtmpaddr noprefixroute dynamic valid_lft 86082sec preferred_lft 86082sec inet6 fe80::a511:9db1:3f4:91f/64 scope link valid_lft forever preferred_lft forever
scope global
indique l'adresse publique directement accessible depuis l'internet munie du sélecteur de réseau presque toujours /64
soit les 4 premiers groupes qui seront identiques sur le réseau local puis les 4 derniers qui formeront l'adresse publique directe unique de la machine dans ce réseau. Cette dernière partie est calculée automatiquement en fonction de paramètres uniques — et résistants aux coupures électriques ! — comme un numéro de série. Le risque de collision est quasi nul.
scope link
désigne l'adresse du réseau local, privée et non routable. Elle débute toujours par fe80
.
::1
où tout est à zéro sauf le dernier bit est l'analogue du 127.0.0.1
en IPv4.
eth0
, s'appelle parfois aussi enx...
, enpNsN
ou wlp2s0
(WiFi) — PIN
predictable interface name. Sur un même réseau les 64 premiers bits sont identiques, quelque soit l'interface (câble, radio).
L'un des buts de cette procédure est d'associer une IPv6 publique spécifique, service par service, de sorte à les migrer d'une machine à l'autre sans toucher au reste : il suffira de supprimer l'IPv6 de la machine A et de la créer sur la machine B. Les tables de routage se mettent très vite automatiquement à jour. Bien entendu il faudra que l'application et les données soit accessibles depuis B.
Un autre but est d'asssigner une IPv6 spécifique à chaque service web, de sorte à mettre en parallèle, sur la même machine, des logiciels serveurs distinct, par exemple trois serveurs web Apache/PHP
, NGINX/openResty
, Zinc HTTP server
de Pharo/Smalltalk, tous à l'écoute sur le même port standard https/443
mais chacun sur sa propre adresse.
En outre cela permet aussi de lancer différentes instances d'un même serveur sous les login spécifiques d'utilisateurs différents, chacun muni de ses propres droits d'accès.
Enfin, au niveau du « reverse » DNS, cela permet d'associer un nom de serveur différent à chaque adresse. Certains services logiciels imposent pratiquement cette contrainte afin de vérifier que le nom indiqué correspond bien à l'adresse, par exemple un serveur de mail mailx.tartanpion.net
et un serveur DNS ns.tartanpion.net
pourraient fonctionner sur la même machine, chacun sur une adresse dédiée.
Nous allons voir une méthode simple de création d'adresse IPv6 rémanentes fondée sur la convention maison que le dernier segment de 16 bits suffira à distinguer jusqu'à 65 mille adresses IPv6 sur une même machine.
La convention préconise également que l'on choisisse ce segment selon le numéro de port utilisé, de sorte à suggérer le service sous jacent. Bien entendu le port reste nécessaire dans le protocole applicatif, il s'agit d'une simple redondance de confort.
sous login privilégié (voir cette FICOP, section Opérations
).
/etc/myIPv6
qui ajoute (et supprime) les IPv6 à partir de la liste des derniers segments à lui passer en argument
cat > /etc/myIPv6 <<EOD............... #!/bin/sh # jmp@scalaire 2018/12/20 # # Add new IPv6 addresses on all global interfaces (eth0, enx000ab01cd02e, ...) # with last 16 bits segment = \$i # /sbin/ip -o -6 addr list # 2: enx000ab01cd02e inet6 2a01:abcd:7890:e0e0:236e:3d6e:a69d:33c7/64 scope global mngtmpaddr nopr... # => /sbin/ip addr add 2a01:abcd:7890:e0e0:236e:3d6e:a69d:\$i dev enx000ab01cd02e if [ "\$1" != add -a "\$1" != del ] then echo "usage: \$0 add|del [last16bits]+" >&2 exit 1 fi cmd=\$1 shift for last16 in \$@ do /sbin/ip -o -6 addr list | sed -n -E \ "s,^[0-9]+:\s+([[:alnum:]]+)\s+inet6\s+([[:xdigit:]:]+):[[:xdigit:]]*/64 scope global.*,\1 \2:\$last16,p" | while read if6 ip6 do echo "\$0: run(/sbin/ip addr \$cmd \$ip6 dev \$if6)" /sbin/ip addr "\$cmd" "\$ip6" dev "\$if6" done done sleep 3 # wait for avahi ... exit 0 EOD............... chmod 0750 /etc/myIPv6Note : ce script agit sur toutes les interfaces où une adresse de portée globale est détectée.
/etc/myIPv6 add 9999 443 ip -6 addr list /etc/myIPv6 del 9999 /etc/myIPv6 add 9999 443 # => erreur pour 443 qui existe déjà /etc/myIPv6 del 9999 443
systemd
le service en charge de tous les segments désirés
cat > /etc/systemd/system/myIPv6.service <<EOD.......... [Unit] Description=setup other public IPv6 addr After=network-online.target Wants=network-online.target # Before=ssh.service # Before=nginx.service [Service] Environment="SUFX6=9999 443 8080 22222" Type=oneshot RemainAfterExit=yes ExecStart=/bin/sh -c "/etc/myIPv6 add \$SUFX6" ExecStop=/bin/sh -c "/etc/myIPv6 del \$SUFX6" [Install] WantedBy=multi-user.target EOD.......... chmod 0640 /etc/systemd/system/myIPv6.serviceNotes : il est possible de spécifier des
Before=
si l'on veut être certain que ces IPv6 soient disponibles au lancement des services les utilisant. Ou de compter sur le WantedBy=
.
systemctl start myIPv6 # vérification : ip -6 addr list # si erreur ou pour info journalctl -exu myIPv6 systemctl enable myIPv6 # pour redémarrage automatique
/etc/myIPv6
dans chacun des xxx.services
avec son ou ses segments IPv6 spécifiques, par exemple dans sshd.service
, on aura
ExecStartPre=/bin/sh -c "/etc/myIPv6 add 2222" ExecStartPre=/usr/sbin/sshd -t ... # PostStop=/bin/sh -c "/etc/myIPv6 del 2222"
Le script précédent apporte de la souplesse en cas d'allocation ou de supression dynamique au long du doux et monotone ronronnement d'un serveur qui jamais ne s'arrête, observant deci delà des va-et-vient de services et d'IP.
Si l'on souhaite des IPv6 fixées pour l'éternité, on peut naturellement les intégrer dans un plan de routage fixe, typiquement dans /etc/network/interfaces
(ou /etc/netplan/XXX.yaml
sous Ubuntu) ou encore, en cas d'allocation dynamique de ces adresses à la DHCP, on peut créer un script spécifique pour Network-manager / systemd
. Par exemple
cat > /etc/network/if-up.d/fixed_IPv6 <<EOD............... #!/bin/sh # jmp@scalaire 2019/02/25 -- rajoute des IPv6 fixes sur $THIS_IFACE # TODO : check first segments == network prefix # or better just concat last 64 bits (4 segmt) to net prefix # (see $IP6_ROUTE too) THIS_IFACE="enp1s0" # PIN for eth1 FIXEDipv6="" FIXEDipv6="$FIXEDipv6 2a01:e7a:1d2:e030:2a84:7d:0100:443" # client 100 web FIXEDipv6="$FIXEDipv6 2a01:e7a:1d2:e030:2a84:7d:0200:443" # client 200 web FIXEDipv6="$FIXEDipv6 2a01:e7a:1d2:e030:2a84:7d:0200:025" # 200 bulk mail FIXEDipv6="$FIXEDipv6 2a01:e7a:1d2:e030:2a84:7d:0500:443" # client 500 web if [ "$IFACE"="$THIS_IFACE" ] && [ "$MODE"="start" ] then for ip6 in $FIXEDipv6 do CMD6="/sbin/ip addr add $ip6 dev $IFACE" echo "$0: run($CMD6)" $CMD6 done fi exit 0 EOD............... chmod 0750 /etc/network/if-up.d/fixed_IPv6Ce script possède le mérite d'être automatiquement appelé à chaque remontage du lien ethernet (i.e. en cas de débranchage malheureux de la mauvaise prise ...)