更新履歴
2020/08/02
いつのまにかスクリプト内で発行するnft
コマンドのオプション-a
が先頭にないとエラーになっていたので、修正しました。
概要
squidでActiveDirectory連携とSSLインターセプトするProxyをdockerで手軽につくる
Docker Composeでネットワークサービス群を5分で作れるようにした(dhcp/radius/proxy/tftp/syslog/dns)
上記のエントリでつくったProxyにULAのIPv6 Onlyな環境からアクセスしようとしたら、できなかった。
以下、Windowsの状況ですが、iOSとAndroidも混在しているので、DHCPv6が使えず(AndroidがDHCPv6つかえない)、ゲートウェイでRAとRDNSS(ドメインサフィックスも付与)を動作させている状態です。
Wireless LAN adapter Wi-Fi:
接続固有の DNS サフィックス . . . . .: prosper2.net
説明. . . . . . . . . . . . . . . . .: Intel(R) WiFi Link 5300 AGN
物理アドレス. . . . . . . . . . . . .: 00-21-6A-CA-4A-A2
DHCP 有効 . . . . . . . . . . . . . .: はい
自動構成有効. . . . . . . . . . . . .: はい
IPv6 アドレス . . . . . . . . . . . .: fd5a:ceb9:ed8d:fe10:70ff:9d38:95b6:9682(優先)
一時 IPv6 アドレス. . . . . . . . . .: fd5a:ceb9:ed8d:fe10:4ca8:def3:2da5:a3b6(優先)
リンクローカル IPv6 アドレス. . . . .: fe80::70ff:9d38:95b6:9682%13(優先)
デフォルト ゲートウェイ . . . . . . .: fe80::b60c:25ff:fe0f:df11%13
DHCPv6 IAID . . . . . . . . . . . . .: 117449066
DHCPv6 クライアント DUID. . . . . . .: 00-01-00-01-24-DA-AE-0D-5C-26-0A-2D-95-59
DNS サーバー. . . . . . . . . . . . .: fd5a:ceb9:ed8d:fe0a:10:254:10:251
NetBIOS over TCP/IP . . . . . . . . .: 無効
接続固有の DNS サフィックス検索の一覧:
prosper2.net
なぜ通信できなかったのか
Dockerネットワークは以下のコマンドで作成したものを利用していました。
# docker network create --ipv6 --driver=bridge --subnet=fd5a:ceb9:ed8d:dead::/64 br_infra_net
IPv4のDNATは設定されていた。(ほかのコンテナのものも入ってます)
# nft list chain ip nat PREROUTING ; nft list chain ip nat DOCKER
table ip nat {
chain PREROUTING {
type nat hook prerouting priority -100; policy accept;
fib daddr type local counter packets 42 bytes 6049 jump DOCKER
}
}
table ip nat {
chain DOCKER {
meta l4proto tcp tcp dport 8081 counter packets 2 bytes 104 dnat to 172.18.0.2:8081
meta l4proto tcp tcp dport 53 counter packets 0 bytes 0 dnat to 172.18.0.3:53
meta l4proto udp udp dport 53 counter packets 0 bytes 0 dnat to 172.18.0.3:53
meta l4proto udp udp dport 514 counter packets 10 bytes 3332 dnat to 172.18.0.4:514
meta l4proto tcp tcp dport 8080 counter packets 0 bytes 0 dnat to 172.18.0.5:8080
meta l4proto udp udp dport 1813 counter packets 0 bytes 0 dnat to 172.18.0.6:1813
meta l4proto udp udp dport 1812 counter packets 0 bytes 0 dnat to 172.18.0.6:1812
}
}
IPv6はされてなかった。悲しい。
# nft list chain ip6 nat PREROUTING
table ip6 nat {
chain PREROUTING {
type nat hook prerouting priority -100; policy accept;
}
}
どうやらコンテナにIPv6ふってるんだからNDPで直接通信してね。
みたいなニュアンスらしい。(違ってたらごめんなさい)
やだ、めんどくさい。
IPv4とおんなじ考え方で通信させたいんだ。
スクリプトで対応した
ちゃんとdockerのマニュアルとか読めば解決策があるような気もするのですが、面倒なのでnftでDNATすることにしました。
IPv4のnftを参考にして、IPv6もおなじようなDNATするスクリプトを作成。
スクリプトは jq
を利用しています。
dnf -y install jq
などでインストールしておく必要があります。
#!/usr/bin/perl
use strict;
my ($buf,$addr,$cnt,$port,$prot,$handle,$cmd);
my $CHAIN = "DOCKER-USER-ipv6-dnat";
if($ARGV[0] !~ /flush|^$/){
print "usage : $0 [ flush ]\n";
exit;
}
####################
# FLUSH RULES
####################
print "---------- FLUSH exist rules and chains ----------\n";
foreach(split(/\n/,`nft -a list chain ip6 nat PREROUTING | grep "jump $CHAIN" 2> /dev/null`)){
chomp($_);
$handle = (split(/\ /,$_))[-1];
$cmd = "nft delete rule ip6 nat PREROUTING handle $handle";
print $cmd."\n";
system("$cmd 2> /dev/null");
}
$cmd = "nft delete chain ip6 nat $CHAIN";
print $cmd."\n";
system("$cmd 2> /dev/null");
if($ARGV[0] eq "flush"){
exit;
}
print "\n";
####################
# NEW RULES
####################
$buf = "";
$buf .= "nft create chain ip6 nat $CHAIN\n";
foreach $cnt (split(/\n/,`docker-compose ps --service`)){
chomp($cnt);
$addr = `docker inspect $cnt | jq '.[].NetworkSettings.Networks[].GlobalIPv6Address'`;
chomp($addr);
$addr =~ s/\"//g;
foreach(split(/\n/,`docker inspect $cnt | jq '.[].HostConfig.PortBindings|keys' | egrep "tcp|udp" `)){
chomp($_);
$_ =~ s/\"|\,|\ //g;
$port = (split(/\//,$_))[0];
$prot = (split(/\//,$_))[1];
#print "$addr : $port $prot \n";
$buf .= "nft add rule ip6 nat $CHAIN meta l4proto $prot $prot dport $port counter dnat to [$addr]:$port\n";
}
}
$buf .= "nft add rule ip6 nat PREROUTING fib daddr type local counter jump $CHAIN\n";
print "---------- CREATE chain and ADD rules ----------\n";
system($buf);
print $buf."\n";
print "---------- CHECK rules and chain ----------\n";
print `nft list chain ip6 nat PREROUTING ; nft list chain ip6 nat $CHAIN`;
exit;
内容は、IPv4のDNATの処理を同じものを、 docker-compose.yml
で生成したコンテナに対して実施しています。
docker-compose.yml
と同じディレクトリにおいて、スクリプトを実行すると、起動しているコンテナに対して docker inspect コンテナ
を実行します。
得られた出力からポートバインドの設定を抜き出して、 nft
の処理を生成しています。
実際に動作させると、以下のようになります。
# ./ipv6_port_bind.pl
---------- FLUSH exist rules and chains ----------
nft delete rule ip6 nat PREROUTING handle 250
nft delete chain ip6 nat DOCKER-USER-ipv6-dnat
---------- CREATE chain and ADD rules ----------
nft create chain ip6 nat DOCKER-USER-ipv6-dnat
nft add rule ip6 nat DOCKER-USER-ipv6-dnat meta l4proto udp udp dport 514 counter dnat to [fd5a:ceb9:ed8d:dead::4]:514
nft add rule ip6 nat DOCKER-USER-ipv6-dnat meta l4proto tcp tcp dport 8081 counter dnat to [fd5a:ceb9:ed8d:dead::2]:8081
nft add rule ip6 nat DOCKER-USER-ipv6-dnat meta l4proto tcp tcp dport 8080 counter dnat to [fd5a:ceb9:ed8d:dead::5]:8080
nft add rule ip6 nat DOCKER-USER-ipv6-dnat meta l4proto udp udp dport 1812 counter dnat to [fd5a:ceb9:ed8d:dead::6]:1812
nft add rule ip6 nat DOCKER-USER-ipv6-dnat meta l4proto udp udp dport 1813 counter dnat to [fd5a:ceb9:ed8d:dead::6]:1813
nft add rule ip6 nat DOCKER-USER-ipv6-dnat meta l4proto tcp tcp dport 53 counter dnat to [fd5a:ceb9:ed8d:dead::3]:53
nft add rule ip6 nat DOCKER-USER-ipv6-dnat meta l4proto udp udp dport 53 counter dnat to [fd5a:ceb9:ed8d:dead::3]:53
nft add rule ip6 nat PREROUTING fib daddr type local counter jump DOCKER-USER-ipv6-dnat
---------- CHECK rules and chain ----------
table ip6 nat {
chain PREROUTING {
type nat hook prerouting priority -100; policy accept;
fib daddr type local counter packets 0 bytes 0 jump DOCKER-USER-ipv6-dnat
}
}
table ip6 nat {
chain DOCKER-USER-ipv6-dnat {
udp dport shell counter packets 0 bytes 0 dnat to [fd5a:ceb9:ed8d:dead::4]:shell
tcp dport tproxy counter packets 0 bytes 0 dnat to [fd5a:ceb9:ed8d:dead::2]:tproxy
tcp dport http-alt counter packets 0 bytes 0 dnat to [fd5a:ceb9:ed8d:dead::5]:http-alt
udp dport radius counter packets 0 bytes 0 dnat to [fd5a:ceb9:ed8d:dead::6]:radius
udp dport radius-acct counter packets 0 bytes 0 dnat to [fd5a:ceb9:ed8d:dead::6]:radius-acct
tcp dport domain counter packets 0 bytes 0 dnat to [fd5a:ceb9:ed8d:dead::3]:domain
udp dport domain counter packets 0 bytes 0 dnat to [fd5a:ceb9:ed8d:dead::3]:domain
}
}
複数回起動しても問題ないように、処理の際には、既存ルールをフラッシュしてから、再作成しています。
nft ~
で始まる行が、実際に発行されるnftコマンドです。
最後に新たに作成したルールとCHAINを表示しています。
これで、ULAなIPv6 Only環境からもDockerコンテナにアクセスできるようになりました。
よかった。