2010/02/12

AlixでのIPv6接続の自動化を試してみる

Alixで作成したブロードバンドルータを再起動した時に、自動でfeel6へ接続しIPv6通信ができるようにしました。 単純にいくつかのスクリプトを作成して、組み合せただけですけどね。

修正 & 作成したスクリプトについて

今回作成したスクリプトは次の通りです。

  • /usr/local/sbin/yadtcpc.pl
  • /usr/local/sbin/ipv6_up.sh
  • /usr/local/sbin/ipv6_down.sh

起動時に呼ばれるスクリプトは"ipv6_up.sh"で、"ipv6_down.sh"は停止時、及び、メンテナンス用のスクリプト。 yadtcpc.plは"ipv6_up.sh"が内部的に呼び出すため、明示的に実行する必要はありません。

/usr/local/sbin/yadtcpc.pl

前回の投稿で紹介したNet::POP3モジュールを使ったDTCPクライアントです。少し変更して、DTCP接続時に渡された情報を標準出力ではなくファイルに出力するようにしました。 接続時には、このファイルから必要な情報を読み取るようにしています。

/var/run/yadtcpc.infoファイル

local=219.xxx.xxx.xxx,remote=43.244.xxx.xx,prefix=2001:03xx:xxxx::,mask=48

また内部では適当なwaitを入れてループしていますが、"/var/run/yadtcpc.control"ファイルから停止の指示があるとquit()により接続を切って全体の処理を中断します。 停止したい場合には$ echo exit | sudo tee /var/run/yadtcpc.controlのようなコマンドを実行します。

前回作成したpackage YADtcpc;はそのまま使い、後ろにあるmain処理全体を次のようなコードで置き換えています。

差し替え個所

...
################
## main class ##
################
package Main;

sub new {
  my ($class) = @_;
  my $self = {
    dtcpc => undef,
    local => undef,
    remote => undef,
    prefix => undef,
    mask => undef,
  
    feel6_remote => "dtcp.feel6.jp",
    feel6_port => 20200,
    feel6_id => undef,
    feel6_password => undef,
  };

  bless $self, $class;
  return $self;
}

sub connect {
  my ($self) = @_;

  if($self->{dtcpc}) {
    $self->{dtcpc}->quit();
    $self->{dtcpc} = undef;
  }
  $self->{dtcpc} = YADtcpc->new($self->{feel6_remote}, Port=>$self->{feel6_port});
  ($self->{local}, $self->{remote}, $self->{prefix},$self->{mask}) = $self->{dtcpc}->dtcp($self->{feel6_id}, $self->{feel6_password});

  $self;
}

sub write_log {
  my ($self, $log_file) = @_;
  if(open(LOG, ">$log_file")) {
    printf LOG "local=%s,remote=%s,prefix=%s,mask=%s\n", $self->{local}, $self->{remote}, $self->{prefix},$self->{mask};
    close(LOG);
  }

  $self;
}

## for debug purpose only
sub print_log {
  my ($self) = @_;
  printf "local=%s,remote=%s,prefix=%s,mask=%s\n", $self->{local}, $self->{remote}, $self->{prefix},$self->{mask};
  $self;
}
sub ping_pong {
  my ($self, $check_file) = @_;
  while ($self->{dtcpc}->ping() =~ /pong/i) {
    if(open(CHECK, $check_file)) {
      my $check = <CHECK>;
      if($check =~ /exit/i) {
        $self->{dtcpc}->quit();
        exit;
      }
      close(CHECK);
    }
    sleep 210; ## essential to send 'ping' within five minutes intervales.
  }

  $self;
}

##########
## main ##
##########
my $main = Main->new();
$main->{feel6_remote} = "dtcp.feel6.jp";
$main->{feel6_port} = 20200;
$main->{feel6_id} = "xxxxxxxx";
$main->{feel6_password} = "xxxxxxxx";

my $info_file = "/var/run/yadtcpc.info";
my $control_file = "/var/run/yadtcpc.control";
do {
  $main->connect();
  $main->write_log($info_file);
  $main->ping_pong($control_file);
  sleep 1;
} while(1);

__END__

あとはPIDを"/var/run/yadtcpc.pid"辺りに書き出して、コマンドの起動時に重複起動のチェックをしようかなと思っています。

/usr/local/sbin/ipv6_up.sh

内部では次のような処理を行なっています。

  • DTCPクライアント(yadtcpc.pl)の起動
  • /var/run/yadtcpc.infoファイルの読み込み
  • デフォルトルートの設定
  • eth1, eth2へのユニキャストアドレスの設定、及びルーティング
  • RAサーバ(radvd)の起動

/usr/local/sbin/ipv6_up.shファイル

#!/bin/bash

umask 022
PATH=/sbin:/usr/sbin:/bin:/usr/bin
LANG=C
export PATH LANG

function ipv4to6addr {
  ## main process
  ipv4_1="$(echo $1 | cut -d'.' -f1)"
  ipv4_2="$(echo $1 | cut -d'.' -f2)"
  ipv4_3="$(echo $1 | cut -d'.' -f3)"
  ipv4_4="$(echo $1 | cut -d'.' -f4)"

  printf "%02x%02x:%02x%02x\n" "${ipv4_1}" "${ipv4_2}" "${ipv4_3}" "${ipv4_4}"
}

## start the my DTCP client
## - first remove the control file
YADTCPC_FILE=/var/run/yadtcpc.control
test -f ${YADTCPC_FILE} && rm ${YADTCPC_FILE}
## - start the client
/usr/local/sbin/yadtcpc.pl &
## - waiting to finish the DTCP configuration
sleep 5

YADTCPC_FILE=/var/run/yadtcpc.info
if test -f ${YADTCPC_FILE}; then
  IPV6_LOCAL="$(cat ${YADTCPC_FILE}|cut -d, -f1|cut -d= -f2)"
  IPV6_REMOTE="$(cat ${YADTCPC_FILE}|cut -d, -f2|cut -d= -f2)"
  IPV6_PREFIX="$(cat ${YADTCPC_FILE}|cut -d, -f3|cut -d= -f2)"
  IPV6_MASK="$(cat ${YADTCPC_FILE}|cut -d, -f4|cut -d= -f2)"
else
  exit 1
fi

## setup sit device
ifconfig sit0 up tunnel ::${IPV6_REMOTE} mtu 1454
route -A inet6 del ::/0 dev eth0
DEV_NAME="$(ifconfig | grep ^sit | grep -v sit0 | head -1 | cut -d' ' -f1)"
test "${DEV_NAME}" && route -A inet6 add ::/0 dev "${DEV_NAME}"

## setup network address
DEV1_IP="$(ip -f inet addr show eth1 | tail -1 | awk '{print $2}' | cut -d/ -f1)"
DEV1_NET="$(echo ${IPV6_PREFIX}|sed -e 's/::/:/')1"
ip -f inet6 addr add ${DEV1_NET}::$(ipv4to6addr ${DEV1_IP})/64 dev eth1
ip -f inet6 route add ${DEV1_NET}::/64 dev eth1

DEV2_IP="$(ip -f inet addr show eth2 | tail -1 | awk '{print $2}' | cut -d/ -f1)"
DEV2_NET="$(echo ${IPV6_PREFIX}|sed -e 's/::/:/')10"
ip -f inet6 addr add ${DEV2_NET}::$(ipv4to6addr ${DEV2_IP})/64 dev eth2
ip -f inet6 route add ${DEV2_NET}::/64 dev eth2

## start radvd
INIT_RADVD=/etc/init.d/radvd
if test -f ${INIT_RADVD}; then
  ${INIT_RADVD} start
fi

/usr/local/sbin/ipv6_down.sh

内部の処理は、ほぼ起動時の処理の逆ですが、既にLAN内部でIPv6を使った接続済みのセッションを切断しないようにデバイスのIPv6アドレス、及び、ルーティング情報は削除していません。

/usr/local/sbin/ipv6_down.shファイル

#!/bin/bash

umask 022
LANG=C
PATH=/sbin:/bin:/usr/bin/:/usr/sbin
export LANG PATH

if test -f /var/run/yadtcpc.info; then
  IPV6_LOCAL="$(cat /var/run/yadtcpc.info|cut -d, -f1|cut -d= -f2)"
  IPV6_REMOTE="$(cat /var/run/yadtcpc.info|cut -d, -f2|cut -d= -f2)"
  IPV6_PREFIX="$(cat /var/run/yadtcpc.info|cut -d, -f3|cut -d= -f2)"
  IPV6_MASK="$(cat /var/run/yadtcpc.info|cut -d, -f4|cut -d= -f2)"
fi

## stop the my DTCP client
echo exit > /var/run/yadtcpc.control

## list up sit+ devices other than sit0
DEV_LIST="$(ifconfig | grep ^sit | grep -v sit0 | cut -d' ' -f1)"

## stop radvd
INIT_RADVD=/etc/init.d/radvd
if test -f ${INIT_RADVD}; then
  ${INIT_RADVD} stop
fi

## down devices
for sit_dev in ${DEV_LIST}
do
  route -A inet6 del ::/0 dev ${sit_dev}
  ip link set ${sit_dev} down
  ip tunnel del ${sit_dev}
done

/etc/network/interfacesファイルの修正

ファイルを配置してから、interfacesファイルを編集します。 再起動の後で$ ping6 www.kame.netが成功する事を確認しています。

interfacesファイル変更後

auto dsl-provider
iface dsl-provider inet ppp
  pre-up /sbin/ifconfig eth0 up # line maintained by pppoeconf
  provider dsl-provider
  post-up /usr/local/sbin/config_iptables.sh
  post-up /usr/local/sbin/config_ip6tables.sh
  post-up /usr/local/sbin/ipv6_up.sh
  pre-down /usr/local/sbin/ipv6_down.sh

0 件のコメント: