BSDRP 1.52に家庭用ブロードバンドルータ的な設定をする
Posted on 2014/10/08(Wed) 00:05 in technical
Summary
今一つ(どころじゃなく)認知度の低いBSDRPを使って、家庭用ブロードバンドルータを設定する手順についてまとめておきます。
ちょっと長いけど、興味のあるところだけつまみ食いして欲しい。
BSDRPというのは、こういうやつです。
BSDRP is an embedded free and open source router distribution based on FreeBSD with Quagga and Bird.
確かに、GUIは無いし、公式アイコンもちょっとあれだけど...
思ったより必要なパッケージは入っているし、FreeBSDの知識はそのまま使えるし、軽量で小回りの利く良いやつだよ。
無線?知らない子ですね...
物理構成
net6501に、BSDRP 1.52のUSBスティックを刺して使います。
USBスティックの作り方は、 http://bsdrp.net/downloads から対象のイメージをダウンロードして、 ddしたりDD for Windowsしたりすればいいので割愛。
構築要件
拡張要件を見据えたソフトウェアの選定および設計をしつつ、基本要件についての設定のみを書きます。
基本要件
- IPv4/IPv6の両方が使用できること
- SSHでアクセスできること
- PPPoEによるIPv4 ISP接続サービスが使用できること
- BBR配下の各ノードにNAPTによるIPv4インターネットアクセスを提供できること
- BBR配下の特定ノードで動作するUDP/IPまたはTCP/IPのサービスを外部に公開できること
- NTPによる時刻同期ができること
- Syslogが使えること
- SNMPが使えること
- 設定の保存と復元が簡単にできること
拡張要件
- L2TPによるIPv6 ISP接続サービスが使用できること
- BBR配下の各ノードにIPv6インターネットアクセスを提供できること
- BBR配下の特定ノードで動作するUDP/IPv6またはTCP/IPv6のサービスを外部に公開できること
- PPTPによるVPNが使用できること
- L2TP/IPsecによるVPNが使用できること
- UPnPによるポート開放が使用できること
- LDAP Clientによるユーザ認証(PAM)が使用できること
設定
設定を始める前に
FreeBSDのシステムに関する設定は、おおよそ /etc/rc.conf に書き込まれます。
従来は vi, echo 等を用いてファイルを直接編集する方法を取る必要がありましたが、 FreeBSD 9.2 または FreeBSD 10.0 以降で導入されているsysrcコマンドも利用することができます。
基本的に、使える部分ではsysrcを使っていきます。
とはいえ、とりあえずはこれだけ知ってればいいでしょう。:
# 追加 # sysrc mpd_enable=YES mpd_enable: -> YES # 変更 # sysrc mpd_enable=NO mpd_enable: YES -> NO # 確認 # sysrc mpd_enable mpd_enable: NO # 削除 # sysrc -x mpd_enable # 変更されている設定を全部表示 # sysrc -a # デフォルトの設定を含め全部表示 # sysrc -A
対象となる設定の書式が不明な場合は、以下の方法が利用できます。
- grep "それらしい検索ワード" /etc/defaults/rc.conf
- sysrc -A | grep "それらしい検索ワード"
例えばこんな感じでしょうか。:
# grep "ssh" /etc/defaults/rc.conf sshd_enable="NO" # Enable sshd sshd_program="/usr/sbin/sshd" # path to sshd, if you want a different one. sshd_flags="" # Additional flags for sshd. # sysrc -A | grep "ssh" sshd_enable: NO sshd_flags: sshd_program: /usr/sbin/sshd
後者の方法は、出力負荷がそれなりにあるので、まずはファイル内検索からしていく方が速いかと思います。
では設定をつらつら書きましょう。
IPアドレスを設定してSSHログインするまではシリアルコンソール(BSDRP(x86)のデフォルト:38400/8/N/1 stop bit/no parity)です。
通報
ちなみに、今回使うnet6501のデフォルトは19200/8/N/1 stop bit/no parityなので、OS側に合わせて揃えておきました。:
> set ConSpeed=38400 > reboot
IP設定
内部向けIPの設定:
# sysrc ifconfig_em1="inet 192.168.0.1 netmask 255.255.255.0" # sysrc ifconfig_em1_ipv6="inet6 2001:db8::1 prefixlen 64" # service netif restart
SSH
BSDRP 1.51以降はSSHがデフォルト無効になったので、手動で有効にします。:
# sysrc sshd_enable="YES" # service sshd start
警告
なぜかsshd_configに PermitRootLogin が2個書かれているので変更するときは要チェック:
# grep -n "PermitRootLogin" /etc/ssh/sshd_config 48:PermitRootLogin yes 96:PermitRootLogin yes
ここから先はSSHが使えるので、ログインできることを確認したら、ログインユーザの制限をします。
以下SSHログインの方法で使い分けます。
公開鍵のみのログインにする場合:
# vi /etc/ssh/sshd_config PermitRootLogin without-password
一般ユーザでログインした後にsudoすればいい場合:
# vi /etc/ssh/sshd_config PermitRootLogin no
rootにパスワード認証でログインしたい場合:
# passwd
System
ホスト名、DNS、タイムゾーン、一般ユーザの追加:
# sysrc hostname="router1.example.com" # echo "nameserver 192.168.0.53" >> /etc/resolv.conf # echo "search example.com" >> /etc/resolv.conf # tzsetup # adduser -D
警告
/homeなんてありませんので、ホームディレクトリは作りません。完全にrootになるためだけの一般ユーザです。 su権限が必要ならwheelを追加。
Quagga
Quaggaは無効にします。:
# service quagga stop # sysrc quagga_enable="NO"
警告
vtyshに入ってhostnameを叩いてwriteすると、show runでは見えるのにzebra.confには保存されないとか、 quaggaの設定有効範囲の確認が手間なので、FreeBSDの基本スタイルで使います。
これで、TCP TIMEWAITが無くなれば、待ち受けポートはかなりすっきりします。:
# netstat -an -p tcp -p udp Active Internet connections (including servers) Proto Recv-Q Send-Q Local Address Foreign Address (state) udp4 0 0 *.514 *.* udp6 0 0 *.514 *.* # sockstat USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS root login 1200 3 dgram -> /var/run/logpriv root syslogd 972 4 dgram /var/run/log root syslogd 972 5 dgram /var/run/logpriv root syslogd 972 6 udp6 *:514 *:* root syslogd 972 7 udp4 *:514 *:* root devd 917 4 stream /var/run/devd.pipe
PPPoE
警告
繋がるとグローバルアドレスが降ってくるので、事前にSSHの設定や余計なサービスが動いていないかなどは再確認。
PPPoEは一般的な家庭で想定される「非固定1IP契約のISP」を想定します。
mpd5の設定をして起動するだけです:
# vi /usr/local/etc/mpd5/mpd5.conf startup: set user admin admin admin set console self 127.0.0.1 5005 set console open set web self 127.0.0.1 5006 set web open default: load pppoe_isp pppoe_isp: create bundle static B1 set iface route default set iface enable tcpmssfix set ipcp ranges 0.0.0.0/0 0.0.0.0/0 create link static L1 pppoe set link action bundle B1 set link max-redial 0 set link mtu 1454 set link mru 1454 set link disable pap chap set link accept chap set auth authname your-username@isp.example.com set auth password your-password set pppoe iface em0 open # sysrc mpd5_enable="YES" # service mpd5 start
通報
startupで設定しているconsoleとwebってのは、 こんな感じ で使える管理コンソールに関する設定です。
ファイアウォールとNAT
グローバルIPが取得できたら、以下の条件でファイアウォールとNATの設定をします。
- 内部ネットワークからは、全てのサービスへのアクセスを即時許可する
- インターネットからは、以下のサービスへのアクセスのみを許可する
- ICMP
- SSH
- DNS
- HTTP
- HTTPS
- 拒否したパケットはサイレントディスカードとする(デフォルトの動き。RSTやICMP Unreachを返さない)
- 内部ネットワークのPCへインターネットアクセスを提供する
- 内部ネットワークからグローバルIPへのサービスアクセスを提供する(Hairpin NAT)
個人的に使い慣れているpfを使用します。:
# vi /etc/pf.conf #--- Interface ext_if = "ng0" int_if = "em1" #--- Address int_subnet = "192.168.0.0/24" dns_server = "192.168.0.53" www_server = "192.168.0.80" dns_server_v6 = "2001:db8::53" www_server_v6 = "2001:db8::80" #--- Service tcp_port = "{22,53,80,443}" udp_port = "{53}" dns_service = "{53}" www_service = "{80,443}" #--- Options set skip on lo0 #--- Normalization scrub in all scrub in on $ext_if all fragment reassemble #--- NAPT nat on $ext_if from $int_subnet to any -> ($ext_if) #--- Redirect rdr pass on $ext_if inet proto {tcp, udp} from any to ($ext_if) port $dns_service -> $www_server rdr pass on $ext_if inet proto tcp from any to ($ext_if) port $www_service -> $www_server #--- Hairpin NAT rdr pass on $int_if proto {tcp, udp} from $int_subnet to ($ext_if) port $dns_service -> $dns_server rdr pass on $int_if proto tcp from $int_subnet to ($ext_if) port $www_service -> $www_server nat pass on $int_if proto {tcp, udp} from $int_subnet to $dns_server port $dns_service -> ($ext_if) nat pass on $int_if proto tcp from $int_subnet to $www_server port $www_service -> ($ext_if) #--- Filter rule block all pass quick on $int_if all pass out all keep state #pass in on $ext_if proto icmp from any to any #pass in on $ext_if proto tcp from any to any port $tcp_port flags S/SA #pass in on $ext_if proto udp from any to any port $udp_port # sysrc pf_enable="YES" # service pf start
インタフェース名の括弧は、意味としてはこうです。
- 括弧無し: 指定したインタフェースを対象にする
- 括弧有り: 指定したインタフェースのアドレスを対象にする
通報
rdr on $ext_if ... のように書く場合は、 pass in on $ext_if ... (コメントアウト部分)を書く必要がありますが、
rdr pass on $ext_if ... のように書く場合は、その後のフィルタがバイパスされるので、 pass in on $ext_if ... を書く必要はありません。
参考: https://www.freebsd.org/cgi/man.cgi?query=pf.conf&sektion=5#TRANSLATION_EXAMPLES
警告
pf.confを読み込むタイミングで、コンフィグ内に書かれているインタフェースにアドレスが設定済みでない場合、 もしくはインタフェースが存在しない場合、コンフィグの読み込みに失敗します。
例えば、mpd5が起動する前にpfが起動するようになっていると、mpd5によって作られるngインタフェースがまだ存在しないため、 pf.confの読み込みに失敗します。(# service -eで起動順序を確認できます)
- 回避方法1: pfよりもmpd5を先に起動するよう、/etc/rc.d/pfの#REQUIRE行にmpd5を追加する
- 回避方法2: mpd5でインタフェースが作られたあと、 set iface up-script を使用してpf.confを再読み込みする
回避方法2は色々面倒なので、ここでは回避方法1を選択したものとします。
pfを選んでいるのは、ipfwだと(拡張が予定されている)UPnPに対応しにくいからです。
性能面ではipfwの方が優れているので、純粋なルータまたはエンドノードでのファイアウォールはipfwの方が良いでしょう。
NTP
NTPは特に何も考えずにntpdを動かしておけばいいかな、と思います。:
# sysrc ntpd_enable="YES" # service ntpd start
設定もデフォルトで実用上問題ないです。
pool.ntp.org とかを見ながら変えても良いでしょう。
起動時にntpdateを動かして、強制的に時刻合わせをする設定もあります。
警告
mpd5の起動よりもntpdateの方が早いので、NTPサーバが外部サーバの場合はあまり効果が見込めないと思いますので、 使用する場合は内部の到達可能なホストをntpdate_hostsで指定するのが良いでしょう。
また、ntpdate_hostsが明示的に指定されていない場合はntp.confを読むようになっているので、ホストの指定が無くても動きます。
使用する場合は:
# sysrc ntpdate_enable="YES" # sysrc ntpdate_hosts="192.168.0.123" # service ntpdate start
という感じです。(serviceコマンドは、動作確認用)
Syslog
syslogサーバにログを向ける場合は、:
# echo "*.* @192.168.0.14" >> /etc/syslog.conf # service syslogd restart
とかで良いんじゃないですかね。
警告
ただこのsyslogdはOS標準のものなので、UDP転送するだけ。TCPとか無い。 それでは不足で、rsyslogやsyslog-ngを使いたい場合は、追加パッケージを入れる必要があります。
デフォルトでは、 syslogd_flags="-s" が使用されており、UDPソケットは空いているものの、自分以外からのsyslogパケットは受け取らないようになっています。
もし、多方面にソケットが空いていること自体が嫌な場合は:
# sysrc syslogd_flags="-s -b 127.0.0.1" # service syslogd restart
もしくは:
# sysrc syslogd_flags="-s -b [::1]" # service syslogd restart
のようにして、ローカルホストからのアクセスのみをソケットが受け付けるようにすることが可能です。
とはいえ、 -b を複数書けないので、IPv6の同時対応を考えると"-s"のままで運用する方が良いんじゃないかと思うのです。
SNMP
FreeBSD標準のSNMPサーバであるところのbsnmpdが利用できます。:
# sysrc bsnmpd_enable=YES # service bsnmpd start
確認には、bsnmpwalkやbsnmpgetというコマンドが使用できます。:
# bsnmpget ifOutOctets.1 ifOutOctets[1] = 1568 # bsnmpwalk 1.3.6.1.2.1.2.2.1.16 ifOutOctets[1] = 1568 ifOutOctets[2] = 322162 ifOutOctets[3] = 0 ifOutOctets[4] = 0 ifOutOctets[5] = 0 ifOutOctets[6] = 143128
bsnmpdのIPv6対応は、 こんな話 もあるんですけど、今のところは使えません。
また、初期状態では全方位からのIPv4アクセスを待ち受けます。:
# sockstat | grep 161 root bsnmpd 2941 8 udp4 *:161 *:*
全方位待ち受けは嫌だという場合は、 /etc/snmpd.config を以下のように書き換えることで、LISTEN IPを変更することができます。:
# grep "begemotSnmpdPortStatus" /etc/snmpd.config #begemotSnmpdPortStatus.0.0.0.0.161 = 1 begemotSnmpdPortStatus.192.168.0.1.161 = 1 # sockstat | grep 161 root bsnmpd 2978 8 udp4 192.168.0.1:161 *:*
もちろん、 TCP Wrapperを使うこともできます ので、そちらで巻き取っても問題ないでしょう。
設定の保存と復元
ではここで、アプライアンスOSとしての利点「設定の保存と復元」についても確認しておきましょう。
BSDRPには、システムコマンドとして "system", "config", "show", "upgrade" が追加されています。
このうち、configでは設定の保存と復元、工場出荷時(この場合は初期設定と言う程度の意味合いですが)に戻す処理を行うことが出来ます。:
# config BSD Router Project configuration tool Usage: /usr/local/sbin/config option - diff [quiet|factory] : Show diff between current and saved config - save : Save current config - apply : Apply current config - rollback : Revert to previous config - put : Put the saved config to a remote server - get : Get config from remote server - factory : Return to default configuration - help (h) [option] : Display this help message. If [option] given, display more detail about the option
最低限必要なのは、config saveを叩くと、config diffで表示されたファイルが保存され、再起動後も有効になる、と言うことです。:
# config diff Looking for differences between running and saved configuration files... host.conf hostid opiekeys rc.conf # config save Archiving previous configuration files... Saving configuration... Done.
また、config putを使うことで、リモートマシンにコンフィグを固めて転送でき、config getで当時のコンフィグにロールバック出来ます。:
# config put scp root@10.0.0.1:/tmp Send saved configuration by SCP to root@10.0.0.1:/tmp Password for root@router.bsdrp.net: router.bsdrp.net.tar.xz 100% 844 0.8KB/s 00:00 # config get scp root@10.0.0.1:/tmp/router.bsdrp.net.tar.xz Get configuration archive SCP from root@10.0.0.1:/tmp/router.bsdrp.net.tar.xz Password for root@router.bsdrp.net: router.bsdrp.net.tar.xz 100% 844 0.8KB/s 00:00 Configuration restored Don't forget confirming your restoration by a 'config save'
また、何を設定したか分からなくなった場合は、工場出荷状態に戻すこともできます。:
# tail -2 /etc/rc.conf ifconfig_em1="inet 192.168.0.1 netmask 255.255.255.0" ifconfig_em1_ipv6="inet6 2001:db8::1 prefixlen 64" # config factory Clear all saved configuration...Done For confirming this action: Reboot and answer 'no' to the question about saving configuration For canceling this action: Simply save the running configuration with 'config save' # tail -2 /etc/rc.conf ifconfig_em1="inet 192.168.0.1 netmask 255.255.255.0" ifconfig_em1_ipv6="inet6 2001:db8::1 prefixlen 64" # reboot Checking if configuration is saved... Warning: Unsaved changes detected ! Looking for differences between running and saved configuration files... host.conf hostid opiekeys rc.conf Do you want to save the configuration before to continue or abort ? (y/n/a): n Rebooting... Shutdown NOW! # tail -2 /etc/rc.conf quagga_daemons="zebra ripd ripngd ospfd ospf6d bgpd isisd"
警告
config factoryは確認なくロールバックされるので、気を付けましょう。
シャットダウン
それでは、コンフィグを保存して終了しましょう。お疲れ様でした。:
# config save Archiving previous configuration files... Saving configuration... Done. # system stop Checking if configuration is saved... Power halting... Shutdown NOW! shutdown: [pid 5173] *** FINAL System shutdown message from root@router.bsdrp.net ***
あ、ちなみにACPIシャットダウンも使えるので、それでも良いです。
おしまい
OSのインストーラと顔を合わせることなく、割と少ない工程で設定できて、お手軽だと思うんですけどそうでもないですかね?
今回は触れていませんが、他にも
- シリアルとVGAのイメージを選べるから組み込み機器でもすんなり使える(起動後は両方使うようにも設定できる。 system dual-console と叩こう)
- LDAP clientも入っているので認証周りも追加が楽
- IPSECやIPSEC_NAT_T付でカーネルコンパイルされているので、IPsecはいきなり設定から入れる
- ROUTETABLES付でカーネルコンパイルされているので、これも最初から使えr(ry
- MROUTING付でカーネルコンパイルされているので、マルチキャストルーティングも使e(ry
- もちろんnetmapもつk(ry
などなど、組み込みやネットワーク周りに関しての初期装備は整っていますので、
折に触れて、お手軽な賑やかしノードとしてご利用ください。
GNS3やご飯のお供にBSDRP。と言われることを夢見て。