EdgeRouterLite-3をGentooで運用しはじめました+IPv6導入(本篇)

前提

  • これまでのネットワークは,BaffaoのBBR-4MGをブロードバンドルータにしてた
  • 100Mなネットワークで,IPv6未対応だったので,IPv6+GbEにしたい
  • 既存ネットワークのトポロジは下図の通り.
  • ただし,これからの記事でアドレスについてはxxxxで伏せさせていただきます
ファイアウォールはBBルーターとパーソナルファイアウォール任せな感じの,よくある一般的なネットワークっぽい.APは諸事情によりRaspberryPiにやらせてて,RaspberryPiにはUSB HDDが接続してありLAN内のファイルサーバとなっている.

これを,次のようにした.

いままで市販のBBルーター任せであんまり考えてなかったファイアウォールルールをイチから見直した事と, 外から自宅にアクセスするために外部にもBBルータの機能で静的ポートフォワードしていたRaspberryPiを, サブネットで分離してちゃんとDMZとして機能するようにさせたところがポイント.とはいえDMZは全部フォワードしてるわけじゃなくて,結局静的ポートフォワードでやってます.

図に書き忘れましたが,IPv4 PPPoEの出口がppp0,IPv6 PPPoEの出口がppp1になってます.

IPv6だと,NATが必要ないのでちょっと設定に戸惑いました.むしろNATとか頭から追い出してちゃんと考えればIPv6のほうがラクっぽいかも.

ネットワーク図がアレゲなのは勘弁してください……
あと,セキュリティの事を言うとまだまだ足りないとこが沢山ある気がしますね.
本当はルーターに色々やらせすぎなんだとおもいますが,ウチは負荷がかかるネットワークではないのでそこは良いかな.

なお,フレッツ系のプロバイダで,IPoEなIPv6が使えない環境だったので,
PPPoEを2セッション張る事にしています.

実際どのようにしたか,以下に記します.
参考: Home Router - Gentoo Wiki

設定(IPv4)

link_ppp0="eth0"
plugins_ppp0="pppoe"
pppd_ppp0="
defaultroute
usepeerdns
"
username_ppp0="xxxx"
password_ppp0="xxxx"
config_ppp0="ppp"
config_ppp1="ppp"
config_eth1="192.168.11.1/24 brd 192.168.1.255"
config_eth2="192.168.1.1/24 brd 192.168.11.255"
dns_servers="24xx:xxxx:x:xxxx::2:1 24xx:xxxx:x:xxxx::1:1 xxx.xxx.xxx.9 xxx.xxx.xxx.1"
view raw net hosted with ❤ by GitHub
このように設定して,
# cd /etc/init.d && ln -s net.lo /etc/init.d/net.ppp0
# rc-update add net.ppp0
# rc-update start net.ppp0
これでIPv4のPPPoEは自動起動します.
ユーザーネーム,パスワード,dnsサーバーはISPから通知されたものを記入しておきます.

次にこれはdnsmasqの設定です.DHCPサーバーと,簡易DNSキャッシュサーバーをやってくれます.他にも色々機能はありますが……
no-resolv
no-poll
interface=eth1
interface=eth2
bind-interfaces
dhcp-range=tag:eth1,192.168.11.2,192.168.11.150,24h
dhcp-range=tag:eth2,192.168.1.2,192.168.1.150,24h
dhcp-host=b8:xx:xx:xx:xx:xx,192.168.1.250,gna
dhcp-host=00:xx:xx:xx:xx:xx,192.168.11.245
dhcp-option=tag:eth1,option:router,192.168.11.1
dhcp-option=tag:eth2,option:router,192.168.1.1
dhcp-authoritative
cache-size=250
log-facility=/var/log/dnsmasq.log
log-queries
log-dhcp
view raw dnsmasq.conf hosted with ❤ by GitHub
とりあえずこのようにeth1とeth2にDHCPを振っておきました.
他にもDMZのRaspberryPiと内部ネットワークのPS3にもMACアドレスに対して固定IPを振ってます.

最後に,iptables.
#!/bin/bash
# clear
iptables -F
iptables -X
iptables -Z
iptables -t nat -F
iptables -t mangle -F
# setting policy
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -P FORWARD DROP
# setting for interface
iptables -A INPUT -i eth1 -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -i eth2 -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT
# reject for source lo and destination localhost
iptables -A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT
# allow all established inbound connections
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
# allow ping
iptables -A INPUT -p icmp --icmp-type 8 ! -i ppp0 -j ACCEPT
# allow dhcp server and client from LAN
iptables -A INPUT -p udp --dport bootps ! -i eth1 -j ACCEPT
iptables -A INPUT -p udp --dport bootps ! -i eth2 -j ACCEPT
iptables -A INPUT -p udp --dport domain ! -i eth1 -j ACCEPT
iptables -A INPUT -p udp --dport domain ! -i eth1 -j ACCEPT
## allow minidlna
iptables -A INPUT -p udp --sport 1900 -i eth2
iptables -A INPUT -p tcp --sport 5000 -i eth2
iptables -A INPUT -p tcp --sport 8200 -i eth2
# setting for forward
iptables -A FORWARD -p tcp -o ppp0 --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
iptables -I FORWARD -i eth1 -d 192.168.11.0/24 -j DROP
iptables -I FORWARD -i eth2 -d 192.168.1.0/24 -j DROP
iptables -A FORWARD -i eth1 -s 192.168.11.0/24 -d 192.168.1.0/24 -j ACCEPT
iptables -A FORWARD -i eth2 -p udp --dport 1900 -s 192.168.1.0/24 -d 192.168.11.0/24 -j ACCEPT
iptables -A FORWARD -i eth2 -p tcp --dport 5000 -s 192.168.1.0/24 -d 192.168.11.0/24 -j ACCEPT
iptables -A FORWARD -i eth2 -p tcp --dport 8200 -s 192.168.1.0/24 -d 192.168.11.0/24 -j ACCEPT
iptables -A FORWARD -i eth1 -o ppp0 -j ACCEPT
iptables -A FORWARD -i eth2 -o ppp0 -j ACCEPT
# setting for nat(ip masquarade)
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
# ip forwarding
iptables -t nat -A PREROUTING -p tcp --dport 22 -i ppp0 -j DNAT --to 192.168.1.xxx
iptables -A FORWARD -i ppp0 -o eth2 -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -m limit --limit 1/s -j LOG --log-prefix "[iptables firewall] : " --log-level=info
view raw iptables.sh hosted with ❤ by GitHub

これでNATが有効になり,パケットがフォワーディングされます.
ここで,RaspberryPiに接続したHDDに録画データを溜めてるのですが,
これをDLNAでPS3から再生したかったので,minidlnaを導入してます.
そしてサブネット越えのため,igmpproxyも導入しました.

参考にしたGentoo WikiはLAN側のサブネットは1つである前提であるため,2つのサブネットのルーターの設定に最初悩みました.特に,dnsmasqのタグ機能に最初気がつかなかったところと,iptablesのフォワードのルール.

設定(IPv6)

まず最初に,IPv6の場合のPPPoEについて調べました.

図はNTT東日本の次世代ネットワークに関する方法のページより,NGN IPv6 ISP接続<トンネル方式> UNI仕様書から拝借.

フレッツ系のISPでIPv6 PPPoE接続の場合,対向サーバーとPPPoEクライアントはリンクローカルアドレスで通信が確立されますが,グローバルアドレスがまだ払われません.
IPv4ではIPCPでアドレスが払われますが,IPv6CPではプレフィクスが払われる直前まででシーケンスが終わってるためです.

なので,ここでDHCPv6-PDにより,プレフィクスを上位より払い出してもらう必要があります.フレッツの場合,/56のプレフィクスが払い出されます.下位64bitは自分で決めて,PPPのインターフェイスにそれを設定する必要があります.

まず,PPPoEの設定について.IPv4の時のコンフィグファイルに次を追記.
更に
# cd /etc/init.d && ln -s net.lo /etc/init.d/net.ppp1
# rc-update add net.ppp1
# rc-update start net.ppp1
次にDHCPv6クライアント.
log-mode full
log-level 8
inactive-mode
insist-mode
iface ppp1 {
rapid-commit yes
pd
}
view raw client.conf hosted with ❤ by GitHub

私は,Gentooのportage treeにあったのでdibblerをつかいました.
dhcpcdISC dhcpだとpppのインターフェイスに対しては使えないので,別の物を使う必要があります.KAMEプロジェクトのWIDE DHCPv6でも良いとおもいます.

dibblerの場合,デーモン起動すると/var/lib/dibbler/以下にxmlでプレフィクス情報等が吐き出されるので,それを使って自分で設定します.
24xx:xxxx:xxxx:xxxx/56が払われたとして,ppp1の下位64bitは0000:0000:0000:0001を割り振るとします.
# ip -6 addr add 24xx:xxxx:xxxx:xxxx::1 dev ppp1
# ip -6 route add dev ppp1

これでルーターからはping6コマンド等で外との疎通を確認できるはずです.

さて,LANのノードにもプレフィクスを教えてやらねばなりません.
そのためには,DHCPv6でステートフルに設定するか,SLAACでステートレスに設定するかの二通りがありますが,私は後者を使いました.

SLAACはRA(Router Advertisation,ルーター広告)を使います.
LAN側にルーターがRAを流せば,LAN側のノードは受け取ったプレフィクスと,自分のイーサネットインターフェイスのMACアドレスを組み合わせて,自動にグローバルアドレスを生成するので楽です.

また,SLAACでグローバルアドレスを設定すると,デフォルトゲートウェイは自動的にRAを流したノードに設定されます.

DNS情報だけは別の手段で(たとえばdnsmasq)教えなければならない……という過去があったようですが,今はRAでDNSも通知できるそうです.

RA通知にはradvdを使いました.radvdのコンフィグは以下です.
interface eth1 {
AdvSendAdvert on;
MinRtrAdvInterval 3;
MaxRtrAdvInterval 10;
AdvDefaultPreference medium;
prefix 24xx:xxxx:xxxx:xxx3::/64 {
AdvOnLink on;
AdvAutonomous on;
AdvRouterAddr off;
AdvPreferredLifetime 20;
AdvValidLifetime 30;
};
};
interface eth2 {
AdvSendAdvert on;
MinRtrAdvInterval 3;
MaxRtrAdvInterval 10;
AdvDefaultPreference medium;
prefix 24xx:xxxx:xxxx:xxx4::/64 {
AdvOnLink on;
AdvAutonomous on;
AdvRouterAddr off;
AdvPreferredLifetime 20;
AdvValidLifetime 30;
};
};
view raw radvd.conf hosted with ❤ by GitHub
これでLANに向けてプレフィクスが広告されます.
よって,IPv4とちがい特にiptablesを設定したりしなくても,個々のノードにIPv6のグローバルアドレスが振られるため通信が可能となります.
しかし,フィルタリングをしないとIPv4+NATよりも脆弱な状況です.

なので最後にIPv6のiptablesを設定しました.
#!/bin/bash
# clear
ip6tables -F
ip6tables -X
ip6tables -Z
# setting policy
ip6tables -P INPUT DROP
ip6tables -P OUTPUT ACCEPT
ip6tables -P FORWARD DROP
# setting for interface
ip6tables -A INPUT -i eth1 -j ACCEPT
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A INPUT -i eth2 -p icmpv6 -j ACCEPT
# allow link local address
ip6tables -A INPUT -s fe80::/10 -j ACCEPT
ip6tables -A OUTPUT -s fe80::/10 -j ACCEPT
# reject for source lo and destination localhost
ip6tables -A INPUT ! -i lo -d ::1/128 -j REJECT
# allow all established inbound connections
ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
ip6tables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
# allow ssh from eth2
ip6tables -A INPUT -i eth2 -p tcp --dport 22 -m state --state NEW -j ACCEPT
# allow ping
ip6tables -A INPUT -p icmpv6 --icmpv6-type 128 -i ppp1 -j ACCEPT
# allow RS,RA,NS,NA
ip6tables -A INPUT -p icmpv6 --icmpv6-type router-solicitation -i ppp1 -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type router-advertisement -i ppp1 -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbor-solicitation -i ppp1 -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbor-advertisement -i ppp1 -j ACCEPT
# setting for forward
ip6tables -A FORWARD -p tcp -o ppp1 --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
ip6tables -I FORWARD -i eth1 -d 24xx:xxxx:xxxx:xxx3::/64 -j DROP
ip6tables -I FORWARD -i eth2 -d 24xx:xxxx:xxxx:xxx4::/64 -j DROP
ip6tables -A FORWARD -i eth1 -o eth2 -j ACCEPT
ip6tables -A FORWARD -i eth1 -o ppp1 -j ACCEPT
ip6tables -A FORWARD -i eth2 -o ppp1 -j ACCEPT
# port forwarding
ip6tables -A FORWARD -i ppp1 -o eth1 -p icmpv6 -j ACCEPT
ip6tables -A FORWARD -i ppp1 -o eth2 -p icmpv6 -j ACCEPT
ip6tables -A FORWARD -i eth2 -p icmpv6 -j ACCEPT
ip6tables -A FORWARD -i ppp1 -o eth2 -p tcp --dport 22 -d 24xx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx -j ACCEPT
view raw ip6tables.sh hosted with ❤ by GitHub

ICMPv6はICMPと違い,ARPの代わりに近隣探索等も熟すので,許可してあります.
が,もうちょっと本当は絞れる気がするので今は試行錯誤しています.

補足

本来,起動スクリプトで,IPv6 PPPoE → dibbler → dibblerが/var/lib/dibblerに出力したxmlをパースしてpppインターフェイスへグローバルアドレス割り当て,ルーティング設定 → さらにそのプレフィクス情報を使ってradvd.confを自動生成 → radvd起動
という風にすべきだとおもいます. しかし,ISPから払い出されるプレフィクスは半固定で,滅多な事がないと変化がないようなので,プレフィクス部分を決め打ちにするコンフィグファイルで対応してしまいました. また,上記設定について,説明を端折りましたが,rc-updateコマンドでそれぞれのデーモンは登録する必要がありますね.