IPv6 PPPoE接続(NGN経由でのIPv6 Internetのために)

はじめに

ここでは、IPv6をNGN経由のPPPoE接続により提供するプロバイダにLinuxにより接続する方法をメモします。

  1. 対象のOSはCentOS5.8です。
  2. インストール時にPPPoEを含む各種のパッケージはすでにインストールされているものとします。
    特に必要なパッケージは
    radvd(radvd-0.9.1-4)
    dhcpv6(dhcpv6-1.0.10-20.el5)
    rp-pppoe(rp-pppoe-3.5-32.1)
    chkconfig(chkconfig-1.3.30.2-2.el5)
    perl(perl関連パッケージ)
    gccおよびKernelヘッダ、ライブラリ群(Wide版dhcpv6のコンパイルに必要)
    です。
  3. インタフェースeth0を使用してPPPoEを張ると共に、ローカルのNWに接続されているものとします。

準備

WIDE版DHCPv6パッケージの導入

CentOS5では、DHCPv6のパッケージとしてDHCP6cが用意されていますが、Prefix Delegationに対応していないため、WIDE版のDHCPv6パッケージを導入します。

# cd /usr/local
# mkdir dhcpv6
# wget "http://sourceforge.jp/frs/g_redir.php?m=jaist&f=%2Fwide-dhcpv6%2Fwide-dhcpv6
%2Fwide-dhcpv6-20080615%2Fwide-dhcpv6-20080615.tar.gz"
--201x-xx-xx 09:16:13-- http://sourceforge.jp/frs/g_redir.php?m=jaist&f=%2Fwide-dhcpv6
%2Fwide-dhcpv6%2Fwide-dhcpv6-20080615%2Fwide-dhcpv6-20080615.tar.gz
sourceforge.jp をDNSに問いあわせています... xxx.xxx.xxx.xxx
sourceforge.jp|xxx.xxx.xxx.xxx|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 302 Found
場所: http://jaist.dl.sourceforge.net/project/wide-dhcpv6/wide-dhcpv6/wide-dhcpv6-20080615/
wide-dhcpv6-20080615.tar.gz 
--20xx-x-02 09:16:13-- http://jaist.dl.sourceforge.net/project/wide-dhcpv6/wide-dhcpv6/
wide-dhcpv6-20080615/wide-dhcpv6-20080615.tar.gz
jaist.dl.sourceforge.net をDNSに問いあわせています... xxx.xxx.xxx.xxx, xxxx:xxxx:xxxx:xxxx::xxxx
jaist.dl.sourceforge.net|xxx.xxx.xxx.xxx|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 215354 (210K) [application/x-gzip]
`wide-dhcpv6-20080615.tar.gz' に保存中
100%[================================================>] 215,354 --.-K/s 時間 0.08s
20xx-xx-xx 09:16:13 (2.64 MB/s) - `wide-dhcpv6-20080615.tar.gz' へ保存完了 [215354/215354]
# 
# tar zxvf wide-dhcpv6-20080615.tar.gz
wide-dhcpv6-20080615
wide-dhcpv6-20080615/addrconf.c
wide-dhcpv6-20080615/addrconf.h
.....(省略).....
wide-dhcpv6-20080615/missing/getifaddrs.c
wide-dhcpv6-20080615/missing/sys
wide-dhcpv6-20080615/missing/sys/queue.h
#
# cd dhcpv6
# ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether make sets $(MAKE)... yes
checking for gcc... gcc
.....(省略).....
checking for stdarg.h... yes
configure: creating ./config.status
config.status: creating Makefile
# make
gcc -g -O2 -I. -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=(以下省略)
.....(省略).....
gcc  -o dhcp6ctl dhcp6_ctlclient.o base64.o auth.o strlcpy.o strlcat.o arc4random.o -lfl
#
# ln -s /usr/local/dhcpv6/wide-dhcpv6-20080615/dhcp6c /usr/local/dhcpv6/dhcp6c
# openssl rand -base64 16 > /usr/local/etc/dhcp6cctlkey

既存のCentOSディストリビューションに含まれるdhcp6バイナリ群との競合/上書きを避けるため、make install は実行しません。

アドレスフォーマット変換ツールの設定

起動スクリプトで使用するIPv6アドレスフォーマット変換のPerlスクリプトを設定します。

ファイルは /opt/ipv6_tools/ipv6_conv として作成します。作成後、実行可能なようにモードを a+x で変更してください。

#!/usr/bin/perl -w
#######################################################################################
#                       IPv6 address format converter
#
# File Name:
#       ipv6_conv
#
# Descriptions:
#       ipv6_conv converts standard ipv6 address nortation to non zero suppress notation
#
#       option -r/--reverse:    print reverse format for DNS
#       option -a/--all:        print non zero suppress notation and reverse format
#
# History(Change log):
#       Version 1.0.0   2011.12.29      jj1req@ca.mbn.or.jp
#               first appeared
#
#       CURRENT_VERSION="1.0.0"
#
#                       Copyright (c) 2011 Kazuhiro WATANABE
#######################################################################################
use strict;
use Getopt::Long;                               # get commandline options
#==================================================================
# subroutines
#==================================================================
#******************************************************************
# convert standard ipv6 address notation to non zero suppress notation
#******************************************************************
sub expand_ipv6( $ )
{
        my @address;
        my @hex_adr;
        my $ipv6 = $_[0];
        if( $ipv6 =~ m/::/ )
        {
                # expand the short form expression to long form.
                my ( $adr_a, $adr_b ) = split( /::/, $ipv6 );
                my @adr_a = split( /:/, $adr_a );
                my @adr_b = split( /:/, $adr_b );
                for (scalar @adr_a .. 7 - scalar @adr_b)
                {
                        push( @adr_a, 0 );
                }
                @address = (@adr_a, @adr_b);
        }
        else
        {
                @address = split( /:/, $ipv6 );
        }
        return( @address );
}
#******************************************************************
#       non option
#******************************************************************
sub conv_nonzero( $ )
{
        my @address = &expand_ipv6( $_[0] );
        my $ipv6 = sprintf( "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
                hex($address[0]), hex($address[1]), hex($address[2]), hex($address[3]),
                hex($address[4]), hex($address[5]), hex($address[6]), hex($address[7])
         );
        return( $ipv6 );
}
#******************************************************************
#       reverse option
#******************************************************************
sub conv_reverse( $ )
{
        my @address = &expand_ipv6( $_[0] );
        my $ipv6 = sprintf( "%04x%04x%04x%04x%04x%04x%04x%04x",
                hex($address[0]), hex($address[1]), hex($address[2]), hex($address[3]),
                hex($address[4]), hex($address[5]), hex($address[6]), hex($address[7])
         );
        my $i;
        my $str;
        my $rev = substr( $ipv6, 31, 1 );
        for( $i=30; $i>=0; $i-- )
        {
                $str = substr( $ipv6, $i, 1 );
                $rev = join( ".", $rev, $str );
        }
        return( $rev );
}
#==================================================================
#               Main
#==================================================================
        my $opt_rev = 0;
        my $opt_all = 0;
        my $ipv6;
        GetOptions( 'reverse' => \$opt_rev, 'all' => \$opt_all );
        if( @ARGV != 1 )
        {
                $ipv6 = <STDIN>;
                chomp( $ipv6 );
        }
        else
        {
                $ipv6 = $ARGV[0];
        }
        unless( $ipv6 =~ /^[0-9a-fA-F:]+$/ )
        {
                print( " Error! argument includes unrecognized character: " . $ipv6 . "\n" );
                exit(1);
        }
        if( $opt_all == 1 )
        {
                print( &conv_nonzero( $ipv6 ) . "\n" );
                print( &conv_reverse( $ipv6 ) . "\n" );
                exit(0);
        }
        if( $opt_rev == 1 )
        {
                print( &conv_reverse( $ipv6 ) . "\n" );
        }
        else
        {
                print( &conv_nonzero( $ipv6 ) . "\n" );
        }
        exit(0);
#******************************************************************
#               End of code.
#******************************************************************

DHCP6cの設定

次に導入したWIDE版DHCP6cに対する設定を行います。

対象のコンフィグファイルは /etc/dhcp6c.conf です。

#
# /etc/dhcp6c.conf
#
interface ppp0 {
        send ia-pd 0;
};
id-assoc pd 0{
        prefix-interface eth0 {
                sla-id 1;
                sla-len 0;
        };
};

PPPoEの設定

PPPoEの設定を行います。PPPoEへの接続情報はあらかじめプロバイダからの情報を確認しておいてください。

# NGN IPv6 Tunnel
# Refer to
#     http://www.gcd.org/blog/2011/06/812/
#     http://www.wandin.net/dotclear/index.php?post/2011/02/10/Native-IPv6-with-Internode-
and-CentOS
#     http://www.ln-lab.net/lunar-night.lab/Memo/OCNIPv6/ocnipv6.html
#     http://lists.centos.org/pipermail/centos/2008-July/060532.html
#
USERCTL=yes
BOOTPROTO=dialup
NAME=DSLppp0
DEVICE=ppp0
TYPE=xDSL
ONBOOT=no
#
# Ethernet Interface Name
ETH=eth0
#
# process id file
PIDFILE=/var/run/pppoe-adsl.pid
#
# Don't set Firewall
#
FIREWALL=NONE
#
# print strings waiting for start up
PING=.
#
# clamp advised MSS to 1412 byte
CLAMPMSS=1412
#
#DEFROUTE=yes
# Don't use synchronous PPP
SYNCHRONOUS=no
#PROVIDER=DSLppp0
# keep connection
DEMAND=no
#
# User
USER=xxxxxxx@xxx.xxx.xxx.xxx
#
# PPPD Configuration
# Time out of start up (sec)
CONNECT_TIMEOUT=10
#
# check delay time(sec) for start up
CONNECT_POLL=2
#
PPPD_EXTRA="ipv6 ,"
#
# PPPoE Configuration
# watch dog time(sec) for PPPoE
PPPOE_TIMEOUT=80
#
# retry count for LCP Echo
LCP_FAILURE=3
#
# send interval of LCP Echo
LCP_INTERVAL=20
#
# no request DNS server info.
#USEPEERDNS=no
PEERDNS=no
#
# IPv6 Configuration
IPV6INIT=yes
IPV6_AUTOCONF=no
# Secrets for authentication using CHAP
# client        server  secret                  IP addresses
"xxxxxx@xxx.xxx.xx.xx"     *       "(パスワードを入れる)"

起動スクリプト

実際にPPPoEを張るために、起動スクリプトを用意します。chkconfig により自動起動が可能なように記述します。

ファイルは /opt/ipv6_tools/ipv6_control.sh として作成します。作成後、実行可能なようにモードを a+x で変更してください。

#! /bin/sh
#
#
#   Startup/shutdown script for ipv6_control
#
#   Linux chkconfig stuff:
#
#   chkconfig: 2345 12 88
#   description: Startup/shutdown script for ipv6_control
#   pidfile:
#
#   Copyright 2012 Kazuhiro WATANABE
#
#   These coded instructions, statements, and computer programs are the
#   property of kazuhiro WATANABE.
#
# Source function library.
. /etc/init.d/functions
IP_ADDR_CONV="/opt/ipv6_tools/ipv6_conv"
PPPD_START_COMMAND="/usr/sbin/adsl-start"
PPPD_STOP_COMMAND="/usr/sbin/adsl-stop"
PPPD_CONFIG="/etc/sysconfig/network-scripts/ifcfg-ppp0"
PPPD_PID_FILE="/var/run/ppp0.pid"
DHCP6C_START_COMMAND="/usr/local/dhcpv6/dhcp6c"
DHCP6C_STOP_COMMAND="killproc dhcp6c"
DHCP6C_CONFIG="/etc/dhcp6c.conf"
LAN_IF="eth0"
PPP_IF="ppp0"
RETVAL=0
start_ipv6() {
    test=`/sbin/ifconfig | /bin/grep ${PPP_IF}`
    if [ -n "$test" ] ; then
        echo "${PPP_IF} is already up"
    return 1
    fi
    echo -n $"Starting PPP Connection: "
    # start ppp connection
    ${PPPD_START_COMMAND} ${PPPD_CONFIG} > /dev/null 2>&1
    if [ -e $PPPD_PID_FILE ] ; then
        echo_success;
        /bin/logger -i -p user.info -t ipv6_control "Start PPP Connection: OK"
    else
        echo_failure;
        /bin/logger -i -p user.info -t ipv6_control "Start PPP Connection: NG"
    fi
    echo
    echo -n $"Starting IPv6 DHCP Client: "
    # start dhcp6 client
    ${DHCP6C_START_COMMAND} -c ${DHCP6C_CONFIG} ${PPP_IF} > /dev/null 2>&1
    if [ $? == 0 ] ; then
        echo_success;
        /bin/logger -i -p user.info -t ipv6_control "Start IPv6 DHCP Client: OK"
    else
        echo_failure;
        /bin/logger -i -p user.info -t ipv6_control "Start IPv6 DHCP Client: NG"
    fi
    echo
    echo -n $"Setup routing: "
    # del default gateway
    /sbin/ip -6 route del default > /dev/null 2>&1
    # add default gateway
    /sbin/ip -6 route add default dev ppp0  > /dev/null 2>&1
    if [ $? == 0 ] ; then
        echo_success;
        /bin/logger -i -p user.info -t ipv6_control "Setup routing: OK"
    else
        echo_failure;
        /bin/logger -i -p user.info -t ipv6_control "Setup routing: NG"
    fi
    echo
}
stop_ipv6() {
    echo -n $"Delete routing: "
    # del default gateway
    /sbin/ip -6 route del default dev ppp0 > /dev/null 2>&1
    if [ $? == 0 ] ; then
        echo_success;
        /bin/logger -i -p user.info -t ipv6_control "Delete routing: OK"
    else
        echo_failure;
        /bin/logger -i -p user.info -t ipv6_control "Delete routing: NG"
    fi
    echo
    echo -n $"Stopping IPv6 DHCP Client: "
    # stop dhcp6 client
    /usr/bin/killall ${DHCP6C_START_COMMAND}  > /dev/null 2>&1
    if [ $? == 0 ] ; then
        echo_success;
        /bin/logger -i -p user.info -t ipv6_control "Stop IPv6 DHCP Client: OK"
    else
        echo_failure;
        /bin/logger -i -p user.info -t ipv6_control "Stop IPv6 DHCP Client: NG"
    fi
    echo
    test=`/sbin/ifconfig | /bin/grep ${PPP_IF}`
    if [ -z "$test" ] ; then
        echo "${PPP_IF} is already down"
        return 1
    fi
    echo -n $"Stopping IPv6 PPP Connection: "
    # stop ppp connection
    ${PPPD_STOP_COMMAND} ${PPPD_CONFIG} > /dev/null 2>&1
    killproc pppd
    echo_success;
    /bin/logger -i -p user.info -t ipv6_control "Stop PPP Connection: OK"
    echo
}
show_address() {
    sleep 2
    IP_ADDR=`/sbin/ifconfig | /bin/grep "/56" | /bin/sed -e "s/.*inet6 addr: \(.*\)\/56.*$/\1/"`
    if [ "${IP_ADDR} != "" ]; then
echo -n "  assigned Grobal address = "
        echo "${IP_ADDR}"
        echo -n "  Prefix(64) address = "
        IP_ADDR_LOG=`${IP_ADDR_CONV} ${IP_ADDR}`
        PREFIX_64=`echo "${IP_ADDR}" | /bin/sed -e "s/\(.*:.*:.*:.*\):.*:.*:.*:.*$/\1/"`
        echo  "${PREFIX_64}"
        /bin/logger -i -p user.info -t ipv6_control "IPv6 Address = ${IP_ADDR}(${PREFIX_64}/64)"
    else
echo "No IPv6 Address is assigned"
        /bin/logger -i -p user.info -t ipv6_control "No IPv6 Address is assigned"
    fi
}
set_ipaddress() {
    /sbin/ip -6 route del default via fe80::xxxx:xxxx:xxxx:xxxx dev eth0
    /sbin/ip -6 addr add ${PREFIX_64}::xxxx/64 dev ${LAN_IF}
}
del_ipaddress() {
    /sbin/ip -6 route del ${PREFIX_64}::/64 dev ${LAN_IF}
    /sbin/ip -6 addr del ${PREFIX_64}::xxxx/64 dev ${LAN_IF}
    /sbin/ip -6 route add default via fe80::xxxx:xxxx:xxxx:xxxx dev eth0
}
start_radvd() {
    /bin/cat > /etc/radvd.conf <<EOF
interface eth0
{
    AdvSendAdvert on;
    AdvOtherConfigFlag on;
    MinRtrAdvInterval 30;
    MaxRtrAdvInterval 100;
    prefix ${PREFIX_64}::/64
    {
        AdvOnLink on;
        AdvAutonomous on;
        AdvRouterAddr off;
    };
};
EOF
    /sbin/service radvd start
}
stop_radvd() {
    /sbin/service radvd stop
}
start_dhcp6s() {
    /bin/cat > /etc/dhcp6s.conf <<EOF
interface ${LAN_IF} {
    server-preference 255;
    renew-time 60;
    rebind-time 90;
    prefer-life-time 130;
    valid-life-time 200;
    allow rapid-commit;
    option dns_servers ${PREFIX_64}::xxxx;
    link AAA {
        range ${PREFIX_64}::ffff:1 to ${PREFIX_64}::ffff:100/64;
    };
};
EOF
    /sbin/service dhcp6s start
}
stop_dhcp6s() {
    /sbin/service dhcp6s stop
}
case $1 in
    start)
        /bin/logger -i -p user.info -t ipv6_control "Start IPv6 Control scripts..."
        start_ipv6
        show_address
        set_ipaddress
        start_radvd
        start_dhcp6s
        /bin/logger -i -p user.info -t ipv6_control "IPv6 Control scripts done."
        ;;
    stop)
        /bin/logger -i -p user.info -t ipv6_control "Stop IPv6 Control scripts..."
        show_address
        stop_dhcp6s
        stop_radvd
        del_ipaddress
        stop_ipv6
        /bin/logger -i -p user.info -t ipv6_control "IPv6 Control scripts done."
        ;;
    *)
        echo $"Usage: $0 {start|stop}"
        exit 3
    esac
exit $RETVAL

Chkconfigによる自動起動設定

# ln -s /opt/ipv6_tools/ipv6_control.sh /etc/init.d/ipv6_control
# chkconfig --add ipv6_control
# chkconfig --list ipv6_control
ipv6_control    0:off   1:off   2:on    3:on    4:on    5:on    6:off
#

以上により自動サーバ起動時に自動的にPPPoEによりIPv6接続されます。

起動

まず、コマンドベースで起動してみます。

# service ipv6_control start
Starting PPP Connection:                                   [  OK  ]
Starting IPv6 DHCP Client:                                 [  OK  ]
Setup routing:                                             [  OK  ]
assigned Grobal address = xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
Prefix(64) address = xxxx:xxxx:xxxx:xxxx
RTNETLINK answers: No such process
radvd を起動中:                                            [  OK  ]
dhcp6s を起動中:                                           [  OK  ]
#

Log

ログはSyslogに User facilityで出力されます。Syslogの設定を変更していない場合は/var/log/messageに出力されます。なるべくuserファシリティは別ファイルに出力するように /etc/syslog.confを変更し、logrotateでログのローテーション設定を行ってください。

以上です。

お疲れ様でした。


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS