LoginSignup
0
0

More than 1 year has passed since last update.

IPv4 over IPv6接続その2

Last updated at Posted at 2021-02-22

概要

IPv4 over IPv6接続その1』に引続き、DS-Lite対応ルーター無しでIPv4 over IPv6接続を実現します。
今回は、DHCPv6による自動設定について説明します。

使用するソフトウェア

以下は2020年7月時点の最新のソースコードです。

ビルド

気を付ける点は、デーモンの起動ユーザーの設定です。
デフォルトではdhcpdという名前のユーザーが使用されます。
予めdhcpdユーザーを作成しておくか、以下のように--privsepuserオプションで存在するユーザーを指定します。

$ ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --privsepuser=daemon
$ make
$ sudo make install

インストールされるファイルは以下の通りです。

/etc/dhcpcd.conf
/usr/lib/dhcpcd/dev/udev.so
/usr/libexec/dhcpcd-hooks/01-test
/usr/libexec/dhcpcd-hooks/20-resolv.conf
/usr/libexec/dhcpcd-hooks/30-hostname
/usr/libexec/dhcpcd-hooks/50-ntp.conf
/usr/libexec/dhcpcd-run-hooks
/usr/sbin/dhcpcd
/usr/share/dhcpcd/hooks/10-wpa_supplicant
/usr/share/dhcpcd/hooks/15-timezone
/usr/share/dhcpcd/hooks/29-lookup-hostname
/usr/share/man/man5/dhcpcd.conf.5
/usr/share/man/man8/dhcpcd-run-hooks.8
/usr/share/man/man8/dhcpcd.8

dhcpcd.conf設定

dhcpcd.confはdhcpcdプロジェクトのgithubの説明に沿っていますが、少し変更しています。

noarp
nodev
option domain_name_servers, domain_name, domain_search, host_name
option ntp_servers
option dhcp6_name_servers, dhcp6_domain_search
option classless_static_routes
option interface_mtu
require dhcp_server_identifier
slaac private
  • domain_name_servers等はIPv4用ですので必須ではありません。
  • dhcp6_name_serversがIPv6用のDNSサーバーアドレスを取得する指定です。
  • slaac privateの設定によって、MACアドレスベースではないIPv6アドレスが設定されます。

DNSサーバーアドレス

IPトンネリング設定でgw.transix.jpのIPv6アドレスを設定するため、IPv6のDNSサーバーアドレスが必要です。しかし、NTTから提供されているルーターによっては、必要なDNSサーバアドレスが得られない場合があります。
実施した環境で使用しているルーターはRV-S340NEです。ルーター自身のWAN側のインターフェースはNTTのDNSサーバーアドレスを受け取っていますが、ルーターがLAN側にDHCPv6で払い出すDNSサーバーアドレスはルーター自身のアドレスになっていました。この場合、ルーターがDNS Proxyとして振舞うべきと思いますが、当該ルーターはそのような動作が行われませんでした。
そのため本記事では、ルーターの設定画面から確認したDNSサーバーアドレスを/etc/resolv.confに静的設定することとします。
なお、GoolgeのIPv6 DNSサーバーではgw.transix.jpのアドレスを引くことができません

フックスクリプト

次に、IPアドレス設定のタイミングでIPトンネリングを設定するために、フックスクリプトを使用します。
dhdpcd標準で用意されているフックスクリプトは使用しません。

以下のようなスクリプトを用意します。

#!/bin/bash

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

TUNDEV=dslite
REMOTE_NAME=gw.transix.jp
ENABLE_DEFAULT_GATEWAY=true

TAG=${TUNDEV}[$$]

debug() { logger -p daemon.debug   -t "${TAG}" "$*"; }
info()  { logger -p daemon.info    -t "${TAG}" "$*"; }
warn()  { logger -p daemon.warning -t "${TAG}" "$*"; }
error() { logger -p daemon.err     -t "${TAG}" "$*"; }

run()
{
        debug "$*"
        { "$@" 3>&1 >&2 2>&3 | error --; } 2>&1
        return "${PIPESTATUS[0]}"
}

lookup_remote()
{
        while true
        do
                for interval in 3 3 0
                do
                        remote=$(run ping6 -c1 "${REMOTE_NAME}")
                        remote=${remote##*from }
                        remote=${remote%%: *}

                        [ -n "${remote}" ] && return 0

                        sleep "${interval}"
                done

                [ -d "/sys/class/net/${TUNDEV}" ] && return 1

                sleep 3
        done
}

get_current_tundev()
{
        local info=$(run ip link show "${TUNDEV}")

        curr_addr=${info##*tunnel6 }
        curr_addr=${curr_addr%% *}
        curr_remote=${info##*peer }
        curr_remote=${curr_remote%% *}
}

func_ROUTERADVERT()
{
        if_down=${if_down:-false}
        if_down=${if_down,,}

        if "${if_down}"
        then
                [ -d "/sys/class/net/${TUNDEV}" ] || return 0

                if run ip route show default dev "${TUNDEV}"
                then
                        run ip route del default dev "${TUNDEV}"
                fi

                run ip tunnel del "${TUNDEV}"
                info "Unconfiguration done"
                return 0
        fi

        if [ -z "${nd1_addr1}" ]
        then
                error "No local address information"
                return 1
        fi

        local addr=${nd1_addr1%/*}
        local action=add

        local remote=
        lookup_remote "${REMOTE_NAME}"

        if [ -z "${remote}" ]
        then
                error "Unable to lookup for remote(${REMOTE_NAME}) address"
                return 1
        fi

        if [ -d "/sys/class/net/${TUNDEV}" ]
        then
                local curr_addr=
                local curr_remote=

                get_current_tundev

                if [ "${curr_addr}" == "${addr}" ]
                then
                        debug "Already configured"
                        return 0
                else
                        info "Reconfiguration..."
                        action=change
                fi
        else
                info "Configuration..."
        fi

        local result=0

        run ip tunnel "${action}" "${TUNDEV}" \
                mode ipip6 remote "${remote}" local "${addr}" \
                encaplimit none dev "${interface}"
        result=$((result|$?))

        run ip link set "${TUNDEV}" up
        result=$((result|$?))

        if "${ENABLE_DEFAULT_GATEWAY}"
        then
                run ip route replace default dev "${TUNDEV}"
                result=$((result|$?))
        fi

        case "${result}" in
        0)
                case "${action}" in
                add)    info   "Configuration successfully";;
                change) info "Reconfiguration successfully";;
                esac
                ;;
        *)
                run ip route del default dev "${TUNDEV}"
                run ip tunnel del "${TUNDEV}"
                error "Configuration error"
                ;;
        esac

        return "${result}"
}

case "${reason}" in
ROUTERADVERT)
        "func_${reason}"
        ;;
esac
  • ROUTERADVERTを受け取った時だけ動作します。
  • ローカルのIPv6アドレス情報はnd?_addr?に格納されますが、実施した環境ではnd1_addr1だけ定義されていたため、これだけを使用しています。
  • IPv6アドレスのインターフェースへの設定はdhcpcdが実施してくれますので、IPトンネルの設定だけを行います。
  • lookup_remote()でgw.transix.jpのIPv6アドレスを調べています。何らかの事情で引けなかった場合を考慮してリトライしています。
  • 初回はトンネルデバイスdsliteが存在しないため、ip tunnel addで新規設定します。
  • 何らかの変更が発生して改めてROUTERADVERTを受け取った場合は、IPトンネル設定のremoteとlocalの変化を確認します。変化があった場合、ip tunnel changeで再設定します。
  • トンネルデバイスのリンクアップ(ip link set dslite up)とデフォルトルート設定(ip route replace default dev dslite)は、初回と変更時で同じ処理で問題ありません。

半年以上、問題なく動作しています。

2022/4/12追記
今までIPv4とIPv6の性能比較をしていなかったのですが、Encapsulation limitオプション(encaplimit)がとても重要なことがわかりました。
Linuxではデフォルトは4になっていますが、デフォルトのままだと、IPv4はIPv6の半分にも満たない性能になります。
制限なしの「none」にすることで、ほぼ性能劣化は発生しなくなりました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0