Об IPv6
2018-11-17
Тихо и незаметно наступает эпоха IPv6. Уже можно заполучить IPv6 дома или в офисе, по крайней мере, клиентам ЭР-Телекома. Уже подключают к интернетам только по IPv6, по крайней мере, некоторых клиентов нашего заказчика, где-то в Америке. Уже без проблем можно получить IPv6 адрес для любого сервера любого уровня виртуальности почти у любого хостера или облачного провайдера. Уже встречаются дешманские виртуалки только с IPv6, и с IPv4 через NAT, где проброшен десяток портов.

В IPv4, как помните, адрес 32-битный. Лишь четыре миллиарда адресов. И они закончились ещё в 2011.
В IPv6 адрес уже 128 бит. Этого хватит всем. Всем землянам, по крайней мере. И миллионам их карманных устройств, у каждого.
IPv6 адреса записываются в виде шестнадцатеричных чисел.
Восемь четырёхзначных чисел,
разделённых двоеточием.
Начальные нули в каждом числе можно упустить.
Самую длинную группу из нулевых чисел тоже можно упустить.
В результате адрес localhost выглядит как ::1.
$ ip addr show dev lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
IPv6 адреса на интерфейсе, глядящем в Интернет, выглядят примерно так:
$ ip -6 addr show dev wlp2s0
2: wlp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
inet6 fd9e:ecc8:b68d::13f/128 scope global noprefixroute
valid_lft forever preferred_lft forever
inet6 2a02:ffff:ffff:12f0::13f/128 scope global dynamic noprefixroute
valid_lft 85082sec preferred_lft 2282sec
inet6 fd9e:ecc8:b68d:0:49ba:acb9:11b5:5adb/64 scope global temporary dynamic
valid_lft 597201sec preferred_lft 78558sec
inet6 fd9e:ecc8:b68d:0:fcd2:44e9:bb4d:d28b/64 scope global mngtmpaddr noprefixroute
valid_lft forever preferred_lft forever
inet6 2a02:ffff:ffff:12f0:49ba:acb9:11b5:5adb/64 scope global temporary dynamic
valid_lft 85081sec preferred_lft 2281sec
inet6 2a02:ffff:ffff:12f0:c354:cdb3:9794:b0a/64 scope global dynamic mngtmpaddr noprefixroute
valid_lft 85081sec preferred_lft 2281sec
inet6 fe80::ff0b:c674:5528:a3c8/64 scope link noprefixroute
valid_lft forever preferred_lft forever
Да. IPv6 адресов всегда больше одного.
Адрес, начинающийся с fe80::, который scope link,
присутствует всегда.
Просто, если у вас включен IPv6.
Даже если вы никуда не подключены.
Этот адрес назначается автоматически,
и уникален для данного интерфейса.
Можно считать это неким аналогом адресов 169.254.0.0/16 в IPv4.
Только в IPv4 адрес 169.254 выдаётся только
если не удалось получить адрес другим способом,
например, по DHCP.
И на это иногда уходит несколько секунд
при загрузке ОС.
А в IPv6 адрес fe80:: назначается сразу, локально.
Он конструируется из MAC адреса.
И, в результате, в IPv6 хост
может сразу общаться с другими IPv6 хостами,
правда, в рамках только локальной сети.
Этого вполне достаточно, чтобы запросить публичный маршрутизируемый адрес у ближайшего маршрутизатора. Таким образом, адреса получаются автоматически без привлечения других протоколов. Это называется Router Advertisement.
Адреса раздаются префиксами.
Подсетями чудовищного размера с маской /64.
Прикиньте, да,
1.8e+19 адресов на абонента.
В данном случае у нас виднеется два префикса.
$ sipcalc fd9e:ecc8:b68d:0:49ba:acb9:11b5:5adb/64
-[ipv6 : fd9e:ecc8:b68d:0:49ba:acb9:11b5:5adb/64] - 0
[IPV6 INFO]
Expanded Address - fd9e:ecc8:b68d:0000:49ba:acb9:11b5:5adb
Compressed address - fd9e:ecc8:b68d:0:49ba:acb9:11b5:5adb
Subnet prefix (masked) - fd9e:ecc8:b68d:0:0:0:0:0/64
Address ID (masked) - 0:0:0:0:49ba:acb9:11b5:5adb/64
Prefix address - ffff:ffff:ffff:ffff:0:0:0:0
Prefix length - 64
Address type - Unassigned
Network range - fd9e:ecc8:b68d:0000:0000:0000:0000:0000 -
fd9e:ecc8:b68d:0000:ffff:ffff:ffff:ffff
То, что начинается на fd9e:ecc8: —
это "Unique Local Unicast" (ULA) адреса.
Это аналог 192.168.0.0/16,
или 10.xxx.xxx.xxx
или 172.16.xxx.xxx.
Это немаршрутизируемые адреса,
применимые только в локальной сети.
В данном случае эти адреса нам зачем-то выдал
маршрутизатор на OpenWRT.
$ sipcalc 2a02:ffff:ffff:12f0:49ba:acb9:11b5:5adb/64
-[ipv6 : 2a02:ffff:ffff:12f0:49ba:acb9:11b5:5adb/64] - 0
[IPV6 INFO]
Expanded Address - 2a02:ffff:ffff:12f0:49ba:acb9:11b5:5adb
Compressed address - 2a02:ffff:ffff:12f0:49ba:acb9:11b5:5adb
Subnet prefix (masked) - 2a02:ffff:ffff:12f0:0:0:0:0/64
Address ID (masked) - 0:0:0:0:49ba:acb9:11b5:5adb/64
Prefix address - ffff:ffff:ffff:ffff:0:0:0:0
Prefix length - 64
Address type - Aggregatable Global Unicast Addresses
Network range - 2a02:ffff:ffff:12f0:0000:0000:0000:0000 -
2a02:ffff:ffff:12f0:ffff:ffff:ffff:ffff
А вот префикс 2a02:ffff:ffff:12f0::/64 —
это уже настоящий публичный префикс,
выданный провайдером.
И в этом настоящем префиксе у нас почему-то аж три адреса.
$ ip -6 addr show dev wlp2s0 | grep 2a02
inet6 2a02:ffff:ffff:12f0::13f/128 scope global dynamic noprefixroute
inet6 2a02:ffff:ffff:12f0:49ba:acb9:11b5:5adb/64 scope global temporary dynamic
inet6 2a02:ffff:ffff:12f0:c354:cdb3:9794:b0a/64 scope global dynamic mngtmpaddr noprefixroute
Адрес, помеченный mngtmpaddr, —
это адрес, автоматически назначенный для данного префикса
и данного MAC адреса.
Точнее для EUI-64.
$ ipv6calc -i 2a02:ffff:ffff:12f0:c354:cdb3:9794:b0a/64
Address type: unicast, global-unicast, productive, iid, iid-global, iid-eui64
Interface identifier: c354:cdb3:9794:0b0a
EUI-64 identifier: c1:54:cd:b3:97:94:0b:0a
EUI-64 identifier is a global unique one
У этих адресов беда с безопасностью. Вторая половина IPv6 адреса у вашего компьютера будет всегда одной и той же, куда бы вы не перемещались, и какой бы IPv6 префикс вы не получали. Так можно отследить ваши перемещения.
Поэтому генерируется ещё второй адрес,
помеченный как temporary.
Здесь суффикс уже полностью случайный.
Это называется "Privacy Extension"
(RFC 3041).
$ ipv6calc -i 2a02:ffff:ffff:12f0:49ba:acb9:11b5:5adb/64
Address type: unicast, global-unicast, productive, iid-random, iid, iid-local
Interface identifier: 49ba:acb9:11b5:5adb
Interface identifier is probably generated by privacy extension
Последний адрес выдан DHCPv6. На самом деле, DHCP для IPv6 не особо нужен, и так адреса нормально назначаются. Но иногда, вроде, он нужен. По крайней мере у ЭР-Телекома нужно заполучать префиксы через DHCPv6 внутри PPPoE соединения.
$ ipv6calc -i 2a02:ffff:ffff:12f0::13f/128
Address type: unicast, global-unicast, productive, iid, iid-local
Interface identifier: 0000:0000:0000:013f
Interface identifier is probably manual set
Так под каким адресом мы ходим в интернет? В таблице маршрутизации всё запутанно.
$ ip -6 route show dev wlp2s0
2a02:ffff:ffff:12f0::13f proto kernel metric 600 pref medium
2a02:ffff:ffff:12f0::/64 proto ra metric 600 pref medium
fd9e:ecc8:b68d::13f proto kernel metric 600 pref medium
fd9e:ecc8:b68d::/64 proto ra metric 600 pref medium
fd9e:ecc8:b68d::/48 via fe80::c66e:1fff:feb9:e41b proto ra metric 600 pref medium
fe80::/64 proto kernel metric 256 pref medium
fe80::/64 proto kernel metric 600 pref medium
default via fe80::c66e:1fff:feb9:e41b proto ra metric 600 pref medium
Тут видно, что адрес маршрутизатора (via) указан
в виде локального адреса fe80::.
Локальная сеть, оказывается, имеет большой префикс /48:
fd9e:ecc8:b68d::/48.
Адреса, полученные по DHCPv6,
помечены как proto kernel.
А адреса, полученные через Router Advertising,
помечены как proto ra.
И default маршрут тоже proto ra.
Выходит,
что Router Advertising вроде как предпочтительнее DHCPv6.
А temporary адрес, который случайный,
должен быть предпочтительнее.
И действительно,
Яндекс Интернетометр
говорит,
что наш IPv6 адрес — 2a02:ffff:ffff:12f0:49ba:acb9:11b5:5adb.
Собственно,
остальные адреса и помечены как noprefixroute,
то есть с ними не связаны маршруты.
Похоже, моя домашняя сеть — это какой-то IPv6 ад. На серваках всё проще.
# ip -6 addr show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
inet6 2001:ffff:ffff:19c:5400:ff:fe54:a41/64 scope global mngtmpaddr dynamic
valid_lft 2591971sec preferred_lft 604771sec
inet6 fe80::5400:ff:fe54:a41/64 scope link
valid_lft forever preferred_lft forever
Тут нет DHCPv6.
Тут нет нужды в Privacy Extension,
потому что серваки не ездят по планете.
В результате у нас только два адреса:
автоматический локальный fe80::
и настоящий публичный IPv6.
$ ip -6 route show dev eth0
2001:ffff:ffff:19c::/64 proto kernel metric 256 expires 2591828sec
fe80::/64 proto kernel metric 256
default via fe80::fc00:ff:fe54:a41 proto ra metric 1024 expires 1628sec hoplimit 64
С маршрутами тоже всё просто и понятно.
Сетевые приложения, как правило, предпочитают IPv6 сокеты. Серверный IPv6 сокет способен принимать подключения как по IPv6, так и по IPv4, не пугайтесь.
# ss -lnpt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.1:6379 *:* users:(("redis-server",pid=571,fd=4))
LISTEN 0 128 *:80 *:* users:(("nginx",pid=598,fd=6),("nginx",pid=596,fd=6))
LISTEN 0 128 *:22 *:* users:(("sshd",pid=555,fd=3))
LISTEN 0 128 *:443 *:* users:(("nginx",pid=598,fd=8),("nginx",pid=596,fd=8))
LISTEN 0 128 :::8080 :::* users:(("java",pid=516,fd=39))
LISTEN 0 128 :::80 :::* users:(("nginx",pid=598,fd=7),("nginx",pid=596,fd=7))
LISTEN 0 128 :::22 :::* users:(("sshd",pid=555,fd=4))
LISTEN 0 128 :::443 :::* users:(("nginx",pid=598,fd=9),("nginx",pid=596,fd=9))
А вот для Nginx нужно явно указать слушание обоих протоколов.
server {
listen 80 default_server;
listen 443 ssl default_server;
listen [::]:80 default_server;
listen [::]:443 ssl default_server;
#...
В URL IPv6 адрес
положено брать в квадратные скобки:
http://[2a00:1450:4011:808::1001].
Для IPv6 адресов в DNS предусмотрен
специальный тип записи AAAA.
$ dig +noall +question +answer aaaa google.com
;google.com. IN AAAA
google.com. 299 IN AAAA 2a00:1450:4011:808::1008
У самих DNS серверов, включая публичные DNS гугла, тоже есть IPv6 адреса.
$ dig +noall +question +answer +stats @2001:4860:4860::8888 aaaa google.com
;google.com. IN AAAA
google.com. 271 IN AAAA 2a00:1450:4011:80b::1002
;; Query time: 48 msec
;; SERVER: 2001:4860:4860::8888#53(2001:4860:4860::8888)
;; WHEN: Sat Nov 17 19:38:19 +06 2018
;; MSG SIZE rcvd: 67
$ dig +noall +question +answer +stats @2001:4860:4860::8844 aaaa google.com
;google.com. IN AAAA
google.com. 299 IN AAAA 2a00:1450:4011:80e::1009
;; Query time: 52 msec
;; SERVER: 2001:4860:4860::8844#53(2001:4860:4860::8844)
;; WHEN: Sat Nov 17 19:39:00 +06 2018
;; MSG SIZE rcvd: 67
$ dig +noall +question +answer +stats @2606:4700:4700::1111 aaaa google.com
;google.com. IN AAAA
google.com. 188 IN AAAA 2a00:1450:4011:804::1004
;; Query time: 35 msec
;; SERVER: 2606:4700:4700::1111#53(2606:4700:4700::1111)
;; WHEN: Sat Nov 17 19:40:06 +06 2018
;; MSG SIZE rcvd: 67
$ dig +noall +question +answer +stats @2606:4700:4700::1001 aaaa google.com
;google.com. IN AAAA
google.com. 157 IN AAAA 2a00:1450:4011:804::1004
;; Query time: 35 msec
;; SERVER: 2606:4700:4700::1001#53(2606:4700:4700::1001)
;; WHEN: Sat Nov 17 19:40:37 +06 2018
;; MSG SIZE rcvd: 67
IPv6 вполне поддерживается в соответствующих типах данных PostgreSQL.
postgres=# select network('2a02:ffff:ffff:12f0:49ba:acb9:11b5:5adb/64');
network
--------------------------
2a02:ffff:ffff:12f0::/64
(1 строка)
postgres=# select inet '2a02:ffff:ffff:12f0:49ba:acb9:11b5:5adb/64' && cidr '2a02:ffff:ffff:12f0::/64';
?column?
----------
t
(1 строка)
Вроде как существует возможность, имея только IPv6 адрес, ходить в IPv4 сети. Чтобы занатить IPv6 адреса в IPv4, есть NAT64. Чтобы резолвить то, что резолвится только в IPv4, в IPv6 адреса, есть DNS64.
Доля мирового IPv6 трафика уже доходит до 25%. Так что пора, пора приобщаться к новому Интернету. Пока не поздно.

К сожалению, ЭР-Телеком не выдаёт статические IPv6 префиксы. То есть IPv6 вы попробовать сможете, но вот поднять у себя сервер без DynDNS не выйдет. Ну тоже неплохо.
И не забывайте, что IPv6 — это настоящий адрес. Безо всякого NAT. Так что настраивайте файерволы на маршрутизаторах, чтобы ваши телефоны в вайфае не похакали. В OpenWRT по дефолту всё норм, входящие соединения запрещены, получается как за NAT.