ルーティング系の設定・スクリプト

家においてあるサーバ(Primergy mx130s2)をルータ化した。

ルーティング系が鬼門(正しい設定方法を知らないだけ)だった為、その設定手順のうち 覚えているものをメモっとく。

概要

ざっくりとしたイメージはこんな感じ。

                       +-------------+
  ipv6(ipoe)    +------+             +----------+           +---------+
  ==============|      |             | enp3s0f0 |===========| home-sw |
  -----|ppp1|---|      |             |(100.0/24)|           +----++---+
                |enp4s0|   home-gw   +----------+                ||
  -----|ppp2|---|      |             | enp3s0f1 |           +----++----+
  ==============|      |             |(150.0/24)|===========| home-kvm |
  ipv4(pppoe)   +------+             +----------+           +----------+
                       +-------------+

ppp1はkvm上に乗っている仮想マシンのための通信経路、 ppp2は通常のネット利用時の通信経路。

また、ipv6はipoeによって降ってくる。

無線APとしても動いており、そちらも別セグメントとしている(200.0/24)。

必要なパッケージ

無線AP、pppoe、ルーティング設定等のパッケージを追加。

# pppoe接続
net-dialup/rp-pppoe

# ルーティング設定
sys-apps/iproute2

# プライベート用ipv6を割り振る為
net-misc/radvd

# 無線AP用
net-wireless/hostapd
net-wireless/rfkill

# FW、NATに必要
net-firewall/iptables

# DHCPサーバ 
net-misc/dhcp

# DNSサーバ
net-dns/unbound
net-dns/bind-tools

radvdについてはまた別途。

/etc/conf.d/net

gentooの基本的なネットワーク設定はこちらに記述する。 固定IPだったり、どのモジュールを使うか、等を記載しておく。

# ppp1
rc_net_ppp1_provide="!net"
rc_net_need_ppp1="net.enp4s0"
config_ppp1="ppp"
plugins_ppp1="pppoe"
link_ppp1="enp4s0"
username_ppp1='xxxxxxxxxx@xxxxxxxxxx'
password_ppp1='************'
# pppd_ppp1="defaultroute"
rc_net_ppp1_need="net.enp4s0"

# ppp2
rc_net_ppp2_provide="!net"
rc_net_need_ppp2="net.enp4s0"
config_ppp2="ppp"
plugins_ppp2="pppoe"
link_ppp2="enp4s0"
username_ppp2='xxxxxxxxxx@xxxxxxxxxx'
password_ppp2='************'
# pppd_ppp2="defaultroute"
rc_net_ppp2_need="net.enp4s0"

# WAN enp4s0
config_enp4s0="null"
mtu_enp4s0="1500"
dns_servers_enp4s0="8.8.8.8 8.8.4.4"

# LAN enp3s0f0(home)
config_enp3s0f0="192.168.100.1/24"
rc_net_enp3s0f0_need="net.enp4s0"

# LAN enp3s0f1(kvm)
config_enp3s0f1="192.168.150.1/24"
rc_net_enp3s0f1_need="net.enp4s0"

# WLAN wlp2s0
modules_wlp2s0="!wpa_supplicant !iwconfig"
config_wlp2s0="192.168.200.1/24"
rc_net_wlp2s0_need="net.enp4s0"

マルチセッションでなければpppd_ppp2="defaultroute usepeerdns"あたりを設定すれば問題ない。 今回はどちらの経路でも確実にアクセスできるよう、Googleのpublic DNSを設定している。

初期状態(起動後)

ルーティングは下記が設定される。

home-gw # ip route
xxx.xxx.xxx.xxx dev ppp1  proto kernel  scope link  src yyy.yyy.yyy.yyy 
127.0.0.0/8 via 127.0.0.1 dev lo 
192.168.100.0/24 dev enp3s0f0  proto kernel  scope link  src 192.168.100.1 
192.168.150.0/24 dev enp3s0f1  proto kernel  scope link  src 192.168.150.1 
192.168.200.0/24 dev wlp2s0  proto kernel  scope link  src 192.168.200.1 
xxx.xxx.xxx.xxx dev ppp2  proto kernel  scope link  src xxx.xxx.xxx.xxx

home-gw # ip rule
0:  from all lookup local 
32766:  from all lookup main 
32767:  from all lookup default

このままだとデフォゲが設定されていない為、通信ができない。

/etc/ppp/ip-up.d/99-route.sh, /etc/ppp/ip-down.d/99-route.sh

pppdによってIPアドレスが割り振られた、削除された際にルーティング設定のスクリプトが動くように仕込む。

愚直にスクリプト書いて自動的にルールを設定するようにした。

スクリプト本体

ip-up.dに置くファイルもip-down.dに置くファイルも変わらない為、リンクを貼った。

スクリプト本体は下記のような感じ(以降改修してるかも)。

#!/bin/bash
# need iproute2
#

TABLE_MAIN=main
TABLE_PPP1=50001
TABLE_PPP2=50002

RULENUM_PPP1=40001
RULENUM_PPP2=40002
RULENUM_START=40010
RULENUM_DEFAULT=60000

#
# 現状チェック
#   既存のルーティングが、現在の状況に即しているかチェックする 
#

# 情報収集
PPP1_IP=$( ifconfig ppp1 2>&1 | grep inet | awk '{print $2}' )
PPP2_IP=$( ifconfig ppp2 2>&1 | grep inet | awk '{print $2}' )
PPP1DEST_IP=$( ifconfig ppp1 2>&1 | grep inet | awk '{print $6}' )
PPP2DEST_IP=$( ifconfig ppp2 2>&1 | grep inet | awk '{print $6}' )


# ルートテーブル情報
ROUTE_PPP1_IP=$( ip -4 route show table $TABLE_PPP1 | grep default | awk '{print $3}' )
ROUTE_PPP2_IP=$( ip -4 route show table $TABLE_PPP2 | grep default | awk '{print $3}' )

# ルール情報
RULEFROM_PPP1=$( ip -4 rule list | grep "$RULENUM_PPP1:" | awk '{print $3}')
RULELOOK_PPP1=$( ip -4 rule list | grep "$RULENUM_PPP1:" | awk '{print $5}')
RULEFROM_PPP2=$( ip -4 rule list | grep "$RULENUM_PPP2:" | awk '{print $3}')
RULELOOK_PPP2=$( ip -4 rule list | grep "$RULENUM_PPP2:" | awk '{print $5}')
RULELOOK_DEFAULT=$( ip -4 rule list | grep "$RULENUM_DEFAULT:" | awk '{print $5}')


#
# ルートテーブル作成/修正/削除
#

# ルートテーブルの修正(ppp1)
if [[ "$PPP1DEST_IP" != "$ROUTE_PPP1_IP" ]]
then
    ip -4 route flush table $TABLE_PPP1
    [[ "$PPP1DEST_IP" != "" ]] && ip -4 route add 0/0 via $PPP1DEST_IP table $TABLE_PPP1
fi

# ルートテーブルの修正(ppp2)
if [[ "$PPP2DEST_IP" != "$ROUTE_PPP2_IP" ]]
then
    ip -4 route flush table $TABLE_PPP2
    [[ "$PPP2DEST_IP" != "" ]] && ip -4 route add 0/0 via $PPP2DEST_IP table $TABLE_PPP2
fi

#
# ルール設定/修正/削除
#

# ルールの修正(ppp1)
if [[ "$PPP1_IP" != "$RULEFROM_PPP1" ]]
then
    ip rule delete pref $RULENUM_PPP1
    [[ "$PPP1_IP" != "" ]] && ip -4 rule add from $PPP1_IP table $TABLE_PPP1 pref $RULENUM_PPP1
fi

# ルールの修正(ppp2)
if [[ "$PPP2_IP" != "$RULEFROM_PPP2" ]]
then
    ip rule delete pref $RULENUM_PPP2
    [[ "$PPP2_IP" != "" ]] && ip -4 rule add from $PPP2_IP table $TABLE_PPP2 pref $RULENUM_PPP2
fi

#
# ルールの修正(ppp1 <-> array)
#   for文で複数のルールを一気に設定する
#
for from in "192.168.150.0/24"
do
    RULENUM=$RULENUM_START
    RULEFROM=$(   ip -4 rule list | grep "^$RULENUM:" | awk '{print $3}')
    RULELOOKUP=$( ip -4 rule list | grep "^$RULENUM:" | awk '{print $5}')
    if [[ "$from" != "$RULEFROM" ]]
    then
        ip rule delete pref $RULENUM
        [[ "$PPP1_IP" != "" ]] && ip -4 rule add from $from table $TABLE_PPP1 pref $RULENUM
    fi
    RULENUM_START=$(( $RULENUM_START + 1))
done

# ルールの修正(default)
if [[ "$PPP2_IP" != "" ]] && [[ "$TABLE_PPP2" != "$RULELOOK_DEFAULT" ]]
then
    # 優先してppp2をGWにする
    ip rule delete pref $RULENUM_DEFAULT
    ip -4 rule add from 0/0 table $TABLE_PPP2 pref $RULENUM_DEFAULT
elif [[ "$PPP1_IP" != "" ]] && [[ "$TABLE_PPP1" != "$RULELOOK_DEFAULT" ]]
then
    # 失敗したらppp1をGWにする
    ip rule delete pref $RULENUM_DEFAULT
    ip -4 rule add from 0/0 table $TABLE_PPP1 pref $RULENUM_DEFAULT
elif [[ "$PPP1_IP" = "" ]] && [[ "$PPP2_IP" = "" ]] && [[ "$RULELOOK_DEFAULT" != "" ]]
then
    # 両方IPがなかったらデフォゲなしにする
    ip rule delete pref $RULENUM_DEFAULT
fi

#
# ipv6 setting
# 複数のIPV6を追加する
#

V6IP=$( ifconfig enp4s0 | grep inet6 | grep global | head -n 1 | awk '{print $2}' | cut -d ':' -f-4 )
V6PREFIX="$V6IP::/64"

# IPがない場合は終了
[[ "$V6IP" == "" ]] && exit 0

# 指定V6が存在しない場合、追加する(::1)
ifconfig enp4s0 | grep -F "$V6IP::1" > /dev/null 2>&1
[[ $? -ne 0 ]] && ip -6 addr add $V6IP::1/64 dev enp4s0 preferred_lft 0

# 指定V6が存在しない場合、追加する(::2)
ifconfig enp4s0 | grep -F "$V6IP::2" > /dev/null 2>&1
[[ $? -ne 0 ]] && ip -6 addr add $V6IP::2/64 dev enp4s0 preferred_lft 0

ipv6の設定も行なっているが、本来なら別スクリプトにわけ、cron実行あたりにしたほうが良い。

変数名も適当なので、修正を入れる必要あり。

その他設定

/etc/init.d/のスクリプト内に、need net と書いてあるスクリプトが多数あるが、実際に依存しているインターフェース 起動スクリプトをneedしておかないと、起動のタイミングで不都合が起こる可能性がある。

comments powered by Disqus
カテゴリ
タグ
月別アーカイブ