$Id: pppoe-router.html,v 1.10 2008-07-03 03:24:26+09 taka Exp $

FreeBSD をつかって PPPoverEthernet 対応ローカルルータをつくる

はじめに

昨今 xDSL, ケーブルアクセス などの安価な Mbps クラス接続の一般化により いわゆる「ブロードバンドルータ」と称する PPPoverEthernetクライアント/NAPT機構内蔵ローカルルータが巷にあふれている. ローカルルータといえば昔は多々存在したが2年ほど前まではほとんどが滅びてしまい Cisco2514 や Cisco4x00 + イーサネットモジュール, あるいは Layer3 スイッチくらいしか選択肢がなかったことを考えると隔世の感がある.

これらの持っている PPPoverEthernet クライアント機能は

ということを前提としているものがほとんどである. またこれらは一般に などの機能的に不十分な点があることが多い. (参考文献) あくまでも NAPT 箱であってローカルルータとは言いがたいものがある.

これらの機能は ISDN 時代の BRI ターミナルアダプタ内蔵ダイアルアップルータでは当たり前に設定できた機能であったにも関わらず 「ブロードバンドルータ」と言い出したとたん, その機能の実装がなくなったものがほとんどであるのは非常に疑問である.

こういった機材では OCN エコノミーを代表とする ローカルネットワーク側にグローバルアドレスのアドレスブロックを割り振られるインターネットアクセスサービスから, アクセスラインを PPPoverEthernet 認証による xDSL とした同様のサービス(いわゆる LAN 型接続)に移行することはできない.

もちろん中には問題なく利用できる機材もあるが, パケットフィルタリング機能が非常に貧弱であるものが多いようだ. (参考文献)

ここでは上記のような構成のネットワークで 外界へのゲートウェイとなるルータを FreeBSD を用いて構築することを記述する. また IPv6 ネットワークへの対応も同時に視野にいれる.


ルータの構築

基本的な情報

基本的には 石塚匡哉さん(ishizuka@ish.org)がご自分の Web サイトにてまとめられている情報 「フレッツ ADSL 対応について」 http://www.ish.org/PPPoE/PPPoE.html が基本となる. IPv4 接続のみでよい場合にはほぼこの文献にしたがって構成すればすぐに接続できるだろう.

実装する機能

実装する機能はルータに特化する. アプリケーションレイヤの daemon は極力動かさない.

必要機材

ソフトウェア

FreeBSD 4.3 (必須)
FreeBSD 3.4 以降では ppp (いわゆる iij-ppp) に PPPoverEthernet クライアント機能が付与されているが, セキュリティホール対応および PPP におけるいくつかの問題 が対応されているので 4.3 を利用することとする.
tcpmssd 1.0 (必須)
ports/net/tcpmssd. TCP Max Maximum Segment Size (MSS) を オンザフライで書き換える daemon. Path MTU Discovery 問題の解決に用いる.
ucd-snmp 4.2.3
ports/net/net-snmp. これによりルータのインターフェースのトラフィック情報, CPU 負荷情報を SNMP 経由で取得できる.

ハードウェア

PC 本体 (必須)
手元にあり余っていた NotePC, SotecWinbookBird/100 を用いた. 1995年製造, Pentium100MHz, RAM32MB, 2GB 以上のハードディスクは BIOS がうまく認識できないという, 今となっては骨董品に近いものではあるが 最大 1.5Mbps 程度のトラフィックを捌くには必要十分な演算性能がある. 2Mbps のシリアルを2本喰える Cisco2501 ですら MC68030 なことを考えると強力すぎるくらいだ. 重要な点は NIC を二つ着ける必要があるために PCcard スロットが二つ必要であるということである. 最近の薄型 NotePC では NIC をひとつしかつけることができないものが多いので注意.
PCcard イーサネット NIC 2種類各1枚 (必須)
3Com 589ET (ep), 富士通 FMV-182 (fe) を用意した. いずれも秋葉原のジャンクショップで 1000円未満で入手.
石塚さんの事例においては同じデバイスドライバを用いる PCcard NIC を使ったがためにいくつかの hack を行っているが, 異なるデバイスドライバを使うものであれば設定がより簡単になるのであえて別のドライバを使う NIC としている.
当初は全く同じ 589ET を2枚で実験を行っていたが, どうしても2枚目を活性化させることができずに FMV-182 を追加入手した.

インターネット接続プロバイダ

インターネット接続性は NTTPCコミュニケーションズの提供する Infosphere から BizADSL8 サービスを購入している. ここでは /29 のネットワークアドレスブロックの割り当てを受ける. IPv4 のみで IPv6 到達性の提供がないのが残念である.


ソフトウェアの構成

FreeBSD 4.3 配布物のインストール

ルータとなる PC に FreeBSD 4.3 をハードディスクにインストールする. インストールするカテゴリとしては bin, crypto があれば十分である. カーネル再構築を自力で行う場合には ssys も追加する.

手元の環境では運用環境と開発環境の演算能力にあまりにも差があるので コンパイル等は開発環境上で行い生成したバイナリを運用環境に転送するという方法をとっている.

kernel 再構築

配布されている GENERIC カーネルは不要なデバイスドライバが多く, また必要なものが入っていないので kernel 再構築を行う. module として動的読み込みをさせてもよいが, 不要なアクセスはないに限る. また後述するソリッドステート化の際に kernel の大きさは重要な要素となるのでできる限り kernel 再構築はするべきである.

実際の kernel 再構築手続きに関しては FreeBSD ハンドブック Chapter.7 FreeBSD カーネルのコンフィギュレーション を参照のこと.

kernel config file /usr/src/sys/i386/conf/PPPOE を以下に示す. 基本的に 石塚さんの記述に準ずるがネットワークインターフェースのデバイスドライバは適宜増減させる必要がある.

machine		i386
cpu		I486_CPU
cpu		I586_CPU
cpu		I686_CPU
ident		PPPOE
maxusers	16
options 	INET
options 	INET6
options 	FFS
options 	FFS_ROOT
options 	SOFTUPDATES
options 	MFS
options 	MD_ROOT
options 	NFS
options 	NFS_ROOT
#options 	MSDOSFS
#options 	CD9660
#options 	CD9660_ROOT
options 	PROCFS
options 	COMPAT_43
#options 	SCSI_DELAY=15000
options 	UCONSOLE
options 	USERCONFIG
options 	VISUAL_USERCONFIG
options 	KTRACE
options 	SYSVSHM
options 	SYSVMSG
options 	SYSVSEM
options 	P1003_1B
options 	_KPOSIX_PRIORITY_SCHEDULING
options		ICMP_BANDLIM
options 	KBD_INSTALL_CDEV
device		isa
device		pci
device		fdc0	at isa? port IO_FD1 irq 6 drq 2
device		fd0	at fdc0 drive 0
device		ata0	at isa? port IO_WD1 irq 14
device		atadisk
options 	ATA_STATIC_ID
device		atkbdc0	at isa? port IO_KBD
device		atkbd0	at atkbdc? irq 1 flags 0x2
device		psm0	at atkbdc? irq 12
device		vga0	at isa?
device		sc0	at isa? flags 0x100
device		npx0	at nexus? port IO_NPX irq 13
device		apm0    at nexus? flags 0x20
device		card
device		pcic0	at isa? irq 0 port 0x3e0 iomem 0xd0000
device		sio0	at isa? port IO_COM1 flags 0x10 irq 4
device		sio1	at isa? port IO_COM2 irq 3
device		miibus
device		fe0 at isa? port 0x300
device		ep0
device		ed0	at isa? port 0x280 irq 10 iomem 0xd8000
#device		sn0	at isa? port 0x320 irq 11
pseudo-device	loop
pseudo-device	ether
pseudo-device	tun	2
pseudo-device	pty
pseudo-device	md
pseudo-device	gif	4
pseudo-device	faith	1
pseudo-device	bpf	4
options		IPFIREWALL
options		IPFIREWALL_VERBOSE
options		IPFIREWALL_FORWARD
options		IPFIREWALL_DEFAULT_TO_ACCEPT
options		IPDIVERT
options		IPV6FIREWALL
options		IPV6FIREWALL_VERBOSE
options		IPV6FIREWALL_DEFAULT_TO_ACCEPT
options		MSGBUF_SIZE=40960
options		NETGRAPH
options		NETGRAPH_ETHER
options		NETGRAPH_PPPOE
options		NETGRAPH_SOCKET

この結果,

NICデバイスドライバデバイス名挿入スロット接続ネットワーク
富士通 FMV-182fefe1slot0内部 LANのスイッチへ
3Com 589ETepep0slot1ADSLモデムへ直結
オンボードSMC9000snsn0オンボードdisable
となる.

/etc/ppp/ppp.conf

石塚さんの事例そのままである. device は ADSL モデム側に接続するネットワークインターフェースに応じて適宜変更する.

default:
 set device PPPoE:ep0
 set log Phase Chat LCP IPCP CCP tun command
 set speed sync
 set mru 1492
 #set mtu 1492
 set mtu 1454
 set ctsrts off
 set timeout 0
 accept CHAP
 add default HISADDR
 enable tcpmssfix

bizadsl8:
 set authname login-id@provider.id
 set authkey password

tcpmssd

package ないし ports で ports/net/tcpmssd をインストールする. 起動スクリプトはインストールされないので /usr/local/etc/rc.d/tcpmssd.sh として自分で書く. ここでは tcpmssd は 変数 PORT で 1023 ポートで待ち受けるように設定している.

#!/bin/sh

TCPMSSD=/usr/local/bin/tcpmssd
PORT=1023
MTU=1454

case $1 in
start)
	if [ -x ${TCPMSSD} ]; then
		${TCPMSSD} -p ${PORT} -m ${MTU} && echo -n 'tcpmssd.'
	fi
	;;
stop)
	killall ${TCPMSSD} && echo -n 'tcpmssd.'
	;;
*)
	echo "Usage: `basename $0` {start|stop}"
	exit 64
	;;
esac

exit 0

/etc/rc.conf

OS としての基本設定. pccard_flags に -z を足すことにより, PCcard NIC の認識が終了するまで ネットワークインターフェースの設定処理を待たせている. 詳しくは /etc/rc, /etc/rc.pccard, /etc/rc.network を参照. パケットフィルタ(ipfw)の設定は /etc/rc.firewall ではなく自作の /etc/ipfw.sh で行っている.

# /etc/rc.conf

# global
hostname="entry.cyber-magic.org"
keymap="us.iso-nocaps"
keyrate="fast"
saver="green"

# network
network_interfaces="fe1 ep0 lo0"
tcp_extensions="YES"
gateway_enable="YES"
ifconfig_fe1="inet 202.224.197.190 netmask 255.255.255.248"
ifconfig_ep0="up"

# pccard
pccard_enable="YES"
pccard_mem="DEFAULT"
pccard_beep="2"
pccardd_flags="-z -i 5 -i 7 -i 10 -i 11"

# security
kern_securelevel_enable="1"
log_in_vain="YES"
firewall_enable="YES"
firewall_script="/etc/ipfw.sh"

# daemons
inetd_enable="NO"
portmap_enable="NO"
sendmail_enable="NO"
sshd_enable="YES"
syslogd_enable="YES"
syslogd_flags="-s"
ntpdate_enable="YES"
ntpdate_flags="-u ntp.cyber-magic.org"

# ipv6
ipv6_enable="YES"
ipv6_network_interfaces="fe1"
ipv6_prefix_fe1="2001:200:129"
ipv6_ifconfig_fe1="2001:200:129::1 prefixlen 64 alias"
ipv6_gateway_enable="YES"
ipv6_static_routes="local"
gif_interfaces="gif0"
gifconfig_gif0="202.224.197.190 203.178.140.203"
#ipv6_static_routes="gif0"
#ipv6_route_gif0="default ::"
rtadvd_enable="YES"
rtadvd_interfaces="fe1"

# ipv6 dynamic routing
ipv6_router_enable="YES"
ipv6_router_flags="-A 2001:200:129::/48,gif0 -O 2001:200:129::/48,gif0 -N fe1 -N ep0"

# ppp
ppp_enable="YES"
ppp_mode="ddial"
ppp_profile="bizadsl8"
ppp_nat="NO"

/etc/ipfw.sh

ルールセットNo.64900にて 外向のパケットを tcpmssd に送り込む. IP spoofing, smurf attack, land attack への対応, NetBIOS/SunRPC の遮断以外は原則的に全部開放としている.

#! /bin/sh
#
# packet filtering/forwarding rule for ADSL/PPPoverEthernet Gateway
#
# inside = numbered
# outside = unnumbered
#

fwcmd=/sbin/ipfw
net="202.224.197.184"
mask="255.255.255.248"
broadcast="202.224.197.191"
maskbits="29"
inside_addr="202.224.197.190"

tunnel_if="tun0"
inside_if="fe1"
outside_if="ep0"

ipv6_tunnel_opposite_side="203.178.140.203"

${fwcmd} -f flush 

${fwcmd} add pass all from any to any via lo0
${fwcmd} add pass all from 127.0.0.1 to 127.0.0.1
${fwcmd} add deny log all from any to 127.0.0.0/8

${fwcmd} add pass all from ${inside_addr} to ${net}:${mask} via ${inside_if}
${fwcmd} add pass all from ${net}:${mask} to ${inside_addr} via ${inside_if}

# Reject ip spoofing/smurf attack/land attack
${fwcmd} add deny log all from ${net}:${mask} to any in recv ${tunnel_if}
${fwcmd} add deny log all from 10.0.0.0/8 to any in recv ${tunnel_if}
${fwcmd} add deny log all from 172.16.0.0/12 to any in recv ${tunnel_if}
${fwcmd} add deny log all from 192.168.0.0/16 to any in recv ${tunnel_if}
${fwcmd} add deny log all from any to ${net}:${mask} out xmit ${tunnel_if}
${fwcmd} add deny log all from any to 10.0.0.0/8 out xmit ${tunnel_if}
${fwcmd} add deny log all from any to 172.16.0.0/12 out xmit ${tunnel_if}
${fwcmd} add deny log all from any to 192.168.0.0/16 out xmit ${tunnel_if}

# Allow IPv6 over IPv4 tunnel
#${fwcmd} add pass ipv6 from any to any
${fwcmd} add pass ipv6 from ${inside_addr} to ${ipv6_tunnel_opposite_side}
${fwcmd} add pass ipv6 from ${ipv6_tunnel_opposite_side} to ${inside_addr}

# Reject source route options
${fwcmd} add deny log all from any to any ipoptions ssrr,lsrr

# Reject Outgoing NetBIOS/SunRPC packet
${fwcmd} add deny log tcp from any to any 111,135,137-139,445
${fwcmd} add deny log udp from any to any 111,135,137-139,445

# resolve Path MTU Discovery Problem
# http://renaud.waldura.com/doc/freebsd-pppoe/#pmtu
${fwcmd} add 64900 divert 1023 tcp from any to any out recv ${tunnel_if} xmit ${inside_if} tcpflags syn

# default is pass
${fwcmd} add 65000 pass all from any to any 

/boot.config

NotePC の場合にはモニタとキーボードが不可分であるためにシリアルコンソールになることは有り得ないので意味がないが, 薄型デスクトップ PC でルータを構成する場合にはシリアルコンソールにしておいたほうが利便性がよいので取り上げておく.

-P

/etc/ttys

NotePC で運用する場合でも液晶パネルをしめたままで狭いところに押し込めて使うことが多いだろう. /etc/ttys を編集しシリアルポートからダム端末でログインできるようにしておくと便利である.

ttyd0   "/usr/libexec/getty std.9600"   vt100  on secure


運用

PPP の設定, ipfw の設定が正しくできていれば 起動と同時に PPPoverEthernet による接続が確立し ルータとして動作し始める.

LAN 内部のノードはこのルータに default 経路を向ければ良い.

IPv6 経路は route6d を利用し RIPng にて交換する.

トラフィック測定

ucd-snmp をインストールしたので各種ステータスを SNMP 経由で取得できる.

ucd-snmp の標準設定状態ではネットワークインターフェースのトラフィック情報などを取得できるようになっている. これに対して MRTG などで定期的に情報を吸い出すすることによりルータにかかっている負荷などを測定できる. (動作例)


現在の運用状況

現在はハードウェアを Soekris Engineering Net4501 に交換, ストレージを 32MB コンパクトフラッシュとした. ハードウェアがファンレスで電源装置もスイッチング電源による AC アダプタであるために完全に機械部分を排除した無音化を実現した.

Net4501 は AMD Elan520 の 133MHz 動作 (Amd5x86 133MHz 相当) であるが 処理能力的問題はでていない. 現状の フレッツ ADSL 8Mbps では問題なく ADSL のリンク帯域に準じた速度を得られている.

B フレッツ ベーシックのような 100Mbps 回線上での PPPoverEthernet 処理が必要になった際には処理能力の不足が予想される. その際にはハードウェアの再度の交換が必要になるかも知れない. VIA C3 を利用した小型な箱がいくつか出てきているのでこういったものの採用を検討しても良いだろう.


参考文献


WelcomePage
誤りの指摘, 改善情報等は歓迎します.
高山 啓介 taka at magic.uinet.or.jp