BSDRP 1.52に家庭用ブロードバンドルータ的な設定をする

Posted on 2014/10/08(Wed) 00:05 in technical

Summary

今一つ(どころじゃなく)認知度の低いBSDRPを使って、家庭用ブロードバンドルータを設定する手順についてまとめておきます。

ちょっと長いけど、興味のあるところだけつまみ食いして欲しい。

BSDRPというのは、こういうやつです。

http://bsdrp.net/

BSDRP is an embedded free and open source router distribution based on FreeBSD with Quagga and Bird.

確かに、GUIは無いし、公式アイコンもちょっとあれだけど...

思ったより必要なパッケージは入っているし、FreeBSDの知識はそのまま使えるし、軽量で小回りの利く良いやつだよ。

無線?知らない子ですね...

物理構成

net6501に、BSDRP 1.52のUSBスティックを刺して使います。

bsdrp_bbr_001.jpg

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。と言われることを夢見て。