https://naba-san.hatenablog.com/


IX2015+Ubuntu(CentOS)でFeel6を終端させる。

【追記】
IX2015とtunnelbroker.net(he.net)の組み合わせにおけるIPv6トンネル接続の実践記録については、2010年2月2日の記事をご参照下さい。



【更に追記:2013-06-06】
本稿で扱うfeel6ですが、2013年6月5日付で、サービスの終了が発表されました。
http://start.feel6.jp/announce/#20130605

終了日時は、2013年 7月31日 (水) 12時00分 で、利用者に対しては有料プランである Feel6@DTI への移行がアナウンスされています。
残念ながら、ここここの情報を見る限り、DTCP での接続は難しい上、一般的なルーターを通しての利用には難があるようで、IX利用者として現実的な代替サービスではありません。

他にIX2015で無料で利用できる現実的な選択肢は、HE.net、SixXS.net の他、v6ip.tsukuba.wide.ad.jp(SoftEther) 辺り‥?

前者二つはISP的に利用できる環境が限られたり、海外をピンポンします。当方環境はICMPパケットが返せない為、どちらもNG。

某筑波サーバーは、別途ブリッジ用のVPNクライアントが必要です。feel6にぶら下げるクライアントは、DTCPの認証系さえ動けばCPUパワーは必要ありませんでしたが、今回は Raspberry Pi とかだと速度が出ません。

さて、どうしたもんでしょうか‥

DTCPとは,要は(こちら側から見て)ローカルの終端アドレスが変化するIP-over-IPなわけですね。

やりたいこと

この辺りを参考にLinux機とIX2015を組み合わせてFeel6を終端させます。今回は認証系の操作だけをLinuxにお任せし,トンネリング関係は全てルーターに丸投げすることにします。

これらは,IX2015の下にUbuntuが,NAPTの状態でぶら下がっている環境を想定しています。IX2015とUbuntuでアドレスが異なる場合,Ubuntuがアクセスをかける時にfeel6側から見えるグローバルアドレスに対して,IPIPトンネルが張られます。どちらもがグローバルアドレスを持っているような環境の方は気をつけて下さい。

大まかな手順

1. Ubuntu(又はCentOS)でDTCP認証スクリプトを動かす
2. IX2015(又はIP-over-IPトンネルに対応したルーターなど)でトンネルを設定する

1. UbuntuDTCP認証系を設定する

まずはスクリプトの入手。この辺りに転がってるスクリプトを拝借‥というかコピペ,「/usr/local/sbin/」あたりに「dtcpc」として配置して実行可能な状態にする。中に設定項目が幾つかあるので,環境に合わせて適宜書き換えること。

下記は私の場合の設定例です(ちょっとだけ値を書き換えてます)。

# cd /usr/local/sbin
# vi dtcpc
        • -
#!/usr/bin/perl use Net::POP3; use Digest::MD5; use Getopt::Std; $ConfFile = "/etc/dtcpc/dtcpc.conf"; $AddrFile = "/var/run/dtcpc.addr"; $StopFile = "/tmp/dtcpc.stop"; $LogFile = "/var/log/dtcpc.log"; $RaConf = "/etc/dtcp/radvd.conf"; $ENV{'PATH'} = "/sbin:/usr/sbin:/bin:/usr/bin"; $U_ID = 65534; $G_ID = 65534; $SIG{'TERM'} = $SIG{'INT'} = "sigexit"; our($local, $remote, $prefix, $nbits); getopts('arxdn') || &help; $Repeat = $opt_r; $Debug = $opt_d; if ($opt_x) { open(OUT, ">$StopFile") || die; chown $U_ID, $G_ID, $StopFile; close(OUT); exit 0; } if (-f $AddrFile) { unlink $AddrFile; } open(CONF, $ConfFile) || die; while () { chop; next if /^#/ || /^$/; last; } die unless /^(\S+)\s+(\d+)\s+(\S+)\s+(\S+)$/; $host = $1; $port = $2; $user = $3; $pass = $4; close(CONF); open(LOG, ">>$LogFile") || open(LOG, ">&STDERR"); select(LOG); $| = 1; select(stdout); print LOG &strtime(time), " host=$host port=$port user=$user\n"; if (!open(DTCP, "-|")) { $| = 1; ($(,$)) = ($G_ID, $G_ID); # gid: nogroup ($<,$>) = ($U_ID, $U_ID); # uid: nobody while (! &dtcp($host, $port, $user, $pass) && $Repeat) { sleep 10; print STDERR "reconnecting...\n" if $Debug; } exit 0; } $ret = 1; while () { s/[\r\n]*$//; last unless /^\d+\.\d+\.\d+\.\d+/; ($local, $remote, $prefix, $nbits) = split; # $remote = $_; system "ip -6 route del default dev sit1" unless($opt_n); system "ip -6 tunnel del sit1" unless($opt_n); if (open(OUT, ">$AddrFile")) { print OUT "$remote $prefix $nbits\n"; close(OUT); } print STDERR "execute: ifconfig sit0 up tunnel ::$remote\n" if $Debug; system "ifconfig sit0 up tunnel ::$remote" unless($opt_n); print STDERR "execute: ifconfig eth0 add ${prefix}1/64\n" if $Debug; system "ifconfig eth0 add ${prefix}1/64" unless($opt_n); print STDERR "execute: ip -6 route add default dev sit1\n" if $Debug; system "ip -6 route add default dev sit1" unless($opt_n); if($opt_a){ print STDERR "execute: start radvd.\n" if $Debug; &radvd; } exit 0 unless $Repeat; $ret = 0; } &clear_route; if (-f $AddrFile) { unlink $AddrFile; } exit $ret; sub help { print < opt: -r ; reconnect -x ; stop -d ; debug -a ; start radvd -n ; dtcp only(not connect tunnel) EOF exit 1; } sub dtcp { my ($host, $port, $user, $pass) = @_; my $pop = Net::POP3->new($host, Port => $port, Debug => $Debug); return undef unless $pop; my $banner = ${*$pop}{'net_pop3_banner'}; if ($banner =~ /^(\S+)\s/) { $banner = $1; } else { print LOG &strtime(time), " Unknown banner: $banner\n"; $pop->close(); return undef; } my $md = Digest::MD5->new(); $md->add($user, $banner, $pass); my $cmd = $pop->command('tunnel', $user, $md->hexdigest, 'network'); my $response = $cmd->getline(); $pop->debug_print(0, $response) if $Debug; if ($response =~ /^\+OK\s+(\d+\.\d+\.\d+\.\d+)\s+(\d+\.\d+\.\d+\.\d+)\s+([\d\:a-fA-F]+)\/(\d+)/) { ($local, $remote, $prefix, $nbits) = ($1, $2, $3, $4); } else { $response =~ s/[\r\n]*$//; print LOG &strtime(time), " Unknown response: $response\n"; $pop->close(); return undef; } print LOG &strtime(time), " local=$local remote=$remote network=$prefix/$nbits\n"; print "$local $remote $prefix $nbits\n"; while (1) { sleep 10; my $cmd = $pop->command('ping'); my $pong = $cmd->getline(); $pop->debug_print(0, $pong) if $Debug; unless ($pong =~ /^\+OK pong/) { $pong =~ s/[\r\n]*$//; print LOG &strtime(time), " Unknown pong: $pong\n"; $pop->close(); return undef; } if (-f $StopFile) { my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($StopFile); if ($uid == $U_ID) { print LOG &strtime(time), " found $StopFile, terminating\n"; unlink $StopFile; last; } } } $response = $pop->command('quit')->getline(); $pop->debug_print(0, $response) if $Debug; $pop->close(); return 1; } sub strtime { my ($time) = @_; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time); sprintf("%4d-%02d-%02d %02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec); } sub radvd { my($conf); open(CONF,">$RaConf") || die "Can not write $RaConf\n"; $conf = <<"EOL"; interface eth0 { AdvSendAdvert on; prefix $prefix/64 { AdvOnLink on; AdvAutonomous on; }; }; EOL print CONF $conf; close(CONF); system "/etc/init.d/radvd start"; } sub clear_route { open(ADDR,$AddrFile) || return 1; $_ = ; my($remote, $prefix, $nbits) = split; print STDERR "DEBUG: $remote, $prefix, $nbits\n" if $Debug; if($opt_a){ print STDERR "execute: stop radvd.\n" if $Debug; system "/etc/init.d/radvd stop" unless($opt_n && $opt_a); } print STDERR "execute: ifconfig eth0 del ${prefix}1/64\n" if $Debug; system "ifconfig eth0 del ${prefix}1/64" unless($opt_n); print STDERR "execute: ip -6 route del default dev sit1\n" if $Debug; system "ip -6 route del default dev sit1" unless($opt_n); system "ip -6 tunnel del sit1" unless($opt_n); } sub sigexit { &clear_route; exit; }
        • -
# chmod +x dtcpc

※たぶんPerl用のPOPモジュールが必要になる。

次に認証設定。dtcpcの冒頭に合わせてファイルを配置すること。

# cd /etc/
# mkdir dtcp
# cd dtcp
# vi dtcpc.conf

        • -

# HOST Port ID Password
dtcp.feel6.jp 20200 hoge fuga

        • -

続けてサービスの設定。Linuxマシンが立ち上がった時点で勝手に起動してくれない事には使い勝手が悪すぎるので。

# cd /etc/init.d
# vi dtcpc-login

#!/bin/sh
# chkconfig: 2345 99 03
# description: DTCP Client Login Service

NAME="DTCP-Client Login"
DAEMON=/usr/local/sbin/dtcpc
LOCK=/var/opt/dtcp/dtcpc

STOP=/tmp/dtcpc.stop
START=""

#Functions
service_start()
{
  if [ -e $LOCK ]
  then
    echo "Service $NAME has already started."
    return 1
  else
    echo "Service $NAME starting..."
    $DAEMON -n &
    sleep 1
    while [ -e $START ]
      do
        sleep 1
      done
    echo "done"
    touch $LOCK
    return 0
  fi
}

service_stop()
{
  if ! [ -e $LOCK ]
  then
    echo "Service $NAME is not started."
    return 1
  else
    echo "Service $NAME stopping..."
    $DAEMON -x &
    sleep 1
    while [ -e $STOP ]
      do
        sleep 1
      done
    rm $LOCK
    echo "done"
    return 0
  fi
}

service_reconnect()
{
  $DAEMON r &
  echo  The request was transmitted to $NAME!
}


# Service Management
test -x $DAEMON || exit 0

case "$1" in
start)
  if service_start
  then
    exit 1
  fi
;;
stop)
  if service_stop
  then
    exit 1
  fi
;;
restart)
  service_stop
  if service_start
  then
    exit
  fi
;;
reconnect)
  service_reconnect
;;
 *)

echo "Usage: $0 {start|stop|restart|reconnect}"
exit 1
esac
exit 0

# chmod +x dtcpc-login

気が向いたら,dtcpc-loginからdtcpcの状態が見られるようにするつもり。

最後にサービスの登録。Ubuntuならsysv-rc-conf,CentOSならchkconfig --add dtcpc-loginとかで設定できるはず。

すべて設定できたら,service dtcpc-login startとかで起動させる。スクリプトの認証が成功すると,/var/run/dtcpc.addrのあたりに割り振られたIPv6アドレスとPrefixが書き込まれるので確認すること。

もしサービスを動かしてみて認証がうまくいかないようなら,先に「/usr/local/sbin/dtcpc -n」を実行し,様子を確認してみると良いかもしれない。

2. IX2015でトンネルを設定する

超適当。とりあえずリンクが張れるところまでは確認してるので,後はRAするなりpingするなり好きにして下さい。

ipv6 prefix [PrefixName] 2001:3e0:[YourAddress]::/48
ipv6 route Tunnel0.0

interface [LAN]
ipv6 address 2001:3e0:[YourAddress]::1/64

interface Tunnel0.0
tunnel mode 6-over-4
tunnel destination [DTCP-Server]
no ip address
ipv6 address autoconfig
no shutdown

ご指摘等は大歓迎です。