LINUX.ORG.RU
ФорумAdmin

IPv6, iptables, LXC, NAT - запутался совсем

 , , , ,


0

1

Пытаюсь методом тыка из интереса осилить IPv6. И есть ощущение, что я делаю что-то очень криво и неправильно.
Есть несколько контейнеров LXC и с IPv4 всё отлично. Ещё есть 4 (да, всего) IPv6-адреса, использовать хочу пока один.
Всё, что должно отвечать по сети, живёт в LXC-контейнерах. В одном (10.10.0.4) - nginx, в который нужно перенаправлять 80-ый порт, и задача которого быть прокси к другим контейнерам, но это не суть важно.
Задача: дать доступ к nginx по IPv6-адресу.
Подключаются контейнеры к бридж-девайсу br0 с виртуальной сетью, на хосте для этого iptables-правила сейчас:

-A PREROUTING -i ens3 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.10.0.4:80
-A POSTROUTING -s 10.10.0.0/24 -o ens3 -j MASQUERADE
10.10.0.0/24 - сеть, в которой сидят контейнеры. ens3 - внешний интерфейс, с публичными статическими IPv4 и IPv6 адресами.
Сделал контейнерам первый попавшийся локальный fc00::1/64 для внутреннего IPv6, пытался действовать по аналогии, и вот такое в ip6tables:
-A PREROUTING -i ens3 -p tcp -m tcp --dport 80 -j DNAT --to-destination [fc00::4]:80
-A POSTROUTING -s fc00::/64 -o ens3 -j MASQUERADE
Внутри всё работает - контейнеры могут пинговать друг-друга, хост, хост - контейнеры и т.п. При обращении со стороны по публичному IPv4 адресу - всё также работает как надо, nginx отдаёт страничку. Но при обращении по IPv6 на 80-ый порт - fail, соединение отваливается по таймауту. У хоста IPv6 работает.
Вопрос - что я делаю не так, и как это делают белые люди?

tcpdump в контейнере с nginx (при обращении от меня (ноутбук с Miredo)) по внешнему IPv6 долго думает, потом таки что-то ловит, и пока curl у меня ждёт таймаут, пишет подобное.

P.S. Обнаружил, что не загружены модули nf_nat_ipv6, ip6table_nat, nf_nat_masquerade_ipv6. Делал find по *ipv6*, *ip6*, *nat* т.п., загружал (на хосте) всё, что казалось нужным, но эффекта это не произвело (может кто-то знает список необходимого?). Доходит, что делаю какую-то ересь. Направьте, пожалуйста, на путь истинный.

Сейчас читаю, что с IPv6 лучше назначать сразу глобальный адрес. Но всё ещё не понимаю, как в данном случае это сделать, оставив NAT для IPv4.

Сейчас читаю, что с IPv6 лучше назначать сразу глобальный адрес. Но всё ещё не понимаю, как в данном случае это сделать, оставив NAT для IPv4.

Без dhcp, указываешь просто ip aдрес для интерфейса статитикой и роут через хост или lxdbr*, чаще всего. В LXD c network api это все централизованно делается, правда последний, пока только в master и собранный в lxd-git-master ppa. Для не Ubuntu можно поставить из snap, правда там пока небольшие ограничения есть.

anonymous_sama ★★★★★ ()
Ответ на: комментарий от anonymous_sama

ip aдрес для интерфейса

Простите, думаю - но не могу понять для какого именно :( br0? LXC-шный? LXC у меня с veth, вот примерно так:

lxc.network.type = veth
lxc.network.veth.pair = ve-nginx
lxc.network.link = br0
lxc.network.flags = up
# IPv4
lxc.network.ipv4 = 10.10.0.4/24
lxc.network.ipv4.gateway = 10.10.0.1
# IPv6
lxc.network.ipv6 = fc00::4/64
lxc.network.ipv6.gateway = f00::1
Не могу просто представить пока схему, как это всё связать. Могу в этом конфиге задать контейнеру внешний IPv6 адрес и шлюз, но ведь нужно это как-то связать с br0, а br0 - с внешним интерфейсом хоста?..

fludardes ★★ ()
Последнее исправление: fludardes (всего исправлений: 1)
Ответ на: комментарий от fludardes

tcpdump в контейнере с nginx (при обращении от меня (ноутбук с Miredo)) по внешнему IPv6 долго думает, потом таки что-то ловит, и пока curl у меня ждёт таймаут, пишет подобное.

Я подумал у тебя уже есть ipv6 блок. Просто подними miredo в контейнере тогда и соединяйся с твоим ноутбуком. iptables правила не трогай.

anonymous_sama ★★★★★ ()
Ответ на: комментарий от anonymous_sama

Контейнер на VPS, у которой есть чистый IPv6, без посредников. Но чтобы тестить подключение к нему по IPv6 от себя (у меня IPv6 нет), использую Miredo.

fludardes ★★ ()
Ответ на: комментарий от anonymous_sama

Ну вот я и ищу способ дать ему нормальный IPv6 :) Судя по всему, NATить IPv6 плохой тон, поэтому теперь хочется выдать контейнеру внешний IPv6. Он есть, но не могу понять, как это сделать.

fludardes ★★ ()
Ответ на: комментарий от fludardes

В твоем случае с хожу вижу несколько способов, но с miredo самый простой.
1. Поднять he-ipv6 туннель, на хосте и раздавать ip адреса с блока(radvd etc). Может также не заработать, и пинговать только по внешним адресам среди контейнеров и самого хоста.
2. Сделать macvlan c сетевой карты для контейнера, не каждый провайдер тебе при этом выдаст еще один ip адрес, и такое одобрит. Но ты можешь попросить.
3. miredo, или другой вид туннеля в контейнере.
Да как вариант если на хосте у тебя статика, то ты можешь macvlan для контейнера, и потом просто отдать ipv6 адрес хоста только этому контейнеру.

anonymous_sama ★★★★★ ()
Последнее исправление: anonymous_sama (всего исправлений: 3)
Ответ на: комментарий от fludardes

Да если займешься первым пунктом, то будет круто если поделишься как сделал. У меня не получилось, вот только у меня he-ipv6 был поднят на роутере, а ipv6 адреса расходились на macvlan, и при этом сам хост был за vpn. Поэтому я уже до конца разбираться не стал, учитывая что ipv6 адрес нужен был всего одному контейнеру.

anonymous_sama ★★★★★ ()

В общем, для простоты пока решил на хост поставить nginx, и функцию «роутера» с nginx-контейнера переложить на хостовый nginx. nginx может успешно слушать IPv6, и проксировать куда угодно, iptables использовать не приходится. Ещё у него есть ngx_stream_core_module, который может и TCP, и UDP перекидывать. Пока кажется неплохим вариантом, и весьма простым в реализации, на первый взгляд.

fludardes ★★ ()

Что-то произошло

В общем, появился /64 блок. Но это всё ещё мало, похоже, для решения без костылей. Снова пришлось думать. Долгие копания в гугле, который этот же тред и выдавал иногда на вопросы, привели в конце-концов к чему-то полурабочему, чего не получается понять. Но может кто-то что скажет или кому-то пригодится.
Вешаем на внешний интерфейс один из IPv6-адресов так, чтобы могли выходить в IPv6-интернеты. Создается bridge (br0), с локальной IPv4-сетью (не забыть про iptables и маскардинг), а кроме неё в его конфиге вешаем на него сразу глобальный адрес и подсеть (/96, например, отдадим контейнерам).

IP6=static
Address6=('2a01:2345:6789:0123:ab01::1/96')
Тут часть 2a01:2345:6789:0123 - выданная глобальная подсеть /64, или как-то так.
Ещё нужен radvd, с чем-то таким (копипаста):
interface br0 {
	AdvSendAdvert on;
	AdvManagedFlag off;
	AdvOtherConfigFlag off;

	prefix 2a01:2345:6789:0123:ab01::/96 {
		AdvOnLink on;
		AdvAutonomous on;
		AdvRouterAddr on;
        };
};
Запустить его. Ругнётся на то, что подсеть не /64, но заработает. Ещё, похоже, нужно sysctl net.ipv6.conf.all.forwarding=1. Может и не всем нужно, пока не хочется тыкать.

Для контейнера LXC в конфиг добавлять только:

lxc.network.ipv6 = 2a01:2345:6789:0123:ab01::2/96

И магия. На хосте:
ip neigh add proxy 2a01:2345:6789:0123:ab01::2 dev ens3

Контейнер теперь умеет выходить в IPv6-интернеты, и пингуется извне. Что это было и как эта конструкция из Г и палок работает не особенно ясно, но пускай пока будет так. Страшно перезагружать сервер - вдруг навернётся, хех.

Ссылки, из которых слеплено это: 1, 2

fludardes ★★ ()

а ты основные RFC, касающиеся IPv6, прочитал уже? :)

Harald ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.