OrangePi R2S は $30ドル+送料 で入手できる 2.5GBE x 2, 1GBE x 2 が特徴のRISC-V シングルボードコンピューター。 今回はこれをファイアーウォールに仕立ててみる。
公式サイト: http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-R2S.html
スペック
"OrangePi_R2S_X1_User Manual_v1.0.pdf" p7
ボード外観

"OrangePi_R2S_X1_User Manual_v1.0.pdf" p9
購入から起動まで
USB Type-Cポートに5V 3Aを供給すると電源が入り、Power Indicatorが赤色に点灯する。 eMMCにはデフォルトでOpenWRTが書き込まれていて、これが自動的にブートする。 Ubuntuに変更したければガイドに従いイメージの書き込みを行う。
管理コンソールへの接続
管理コンソールへの接続を行うため、WANではなく、LAN側のいずれかのポートにPCを接続する。 IPv4/IPv6共にDHCPサーバーが有効であるため、PCにIPが自動的に割り当てられる。 ブラウザで http://192.168.2.1 (非TLS)に接続すれば管理コンソールが開く。
"OrangePi_R2S_X1_User Manual_v1.0.pdf" p89
デフォルトのユーザーアカウントは root で、パスワードが設定されていない。
rootのパスワード設定(System -> Administration -> Router Password)

Web管理コンソールのHTTPS化
luci-ssl のインストール
opkg update opkg install luci-ssl uci set uhttpd.main.redirect_https='1' uci commit uhttpd service uhttpd reload
注記: opkg updateで次のエラーが出るが、 luci-sslのようなコアではないものをインストールするのには問題がない。
Downloading https://downloads.openwrt.org/releases/24.10.0/targets/ky/riscv64/packages/Packages.gz *** Failed to download the package list from https://downloads.openwrt.org/releases/24.10.0/targets/ky/riscv64/packages/Packages.gz
上記URL中の ky/riscv64 は この環境の DISTRIB_TARGET だが、公式OpenWrt の標準ターゲットではない。
つまり、RISC-V用の勝手ビルドなので存在しない適当なアドレスになっていて解決策はないはずだが、正しいURLなど、もしエラーを解消する方法があれば教えてください…
root@OpenWrt:~# cat /etc/openwrt_release DISTRIB_ID='OpenWrt' DISTRIB_RELEASE='24.10.0' DISTRIB_REVISION='r28427-6df0e3d02a' DISTRIB_TARGET='ky/riscv64' DISTRIB_ARCH='riscv64_riscv64' DISTRIB_DESCRIPTION='OpenWrt 24.10.0 r28427-6df0e3d02a' DISTRIB_TAINTS='no-all'
~~ファイアーウォール機器にするための設定~~
ここからはファイアーウォール機器にするための設定になります。
現在の設定をバックアップ
sysupgrade -b /tmp/backup.tar.gz
WAN側から管理できるようにする
WAN側からのSSH接続の許可 (Network -> Firewall -> Traffic Rules)

WAN側からWeb管理コンソールへの接続許可 (Network -> Firewall -> Traffic Rules)

WAN側からSSH/Web管理コンソールへ接続する
上記設定後、WAN側から接続して作業を続行します。
ネットワークの再作成
lan, br-lanを破棄してbr-25gを作る
uci delete network.lan sec="$(uci -q show network | sed -n "s/^\(network\.@device\[[0-9]\+\]\)\.name='br-lan'$/\1/p")" echo "br-lan device section = $sec" [ -n "$sec" ] && uci delete "$sec" uci add network device uci set network.@device[-1].name='br-25g' uci set network.@device[-1].type='bridge' uci add_list network.@device[-1].ports='eth2' uci add_list network.@device[-1].ports='eth3' uci set network.@device[-1].stp='0' uci set network.br25g='interface' uci set network.br25g.device='br-25g' uci set network.br25g.proto='none' uci set network.br25g.auto='1' uci commit network /etc/init.d/network reload
ファイアーウォール ルールを再作成
- 基本的なWAN側からのパケットのフィルタ
- WAN側からSSH, Web管理コンソールへアクセスできるようにする
- br-25gの2つのポートについて、eth2が上流、eth3を下流とする
- 下流側の端末からはデフォルトゲートウェイ以外のローカルネットワークの端末にアクセスできないようにする
: > /etc/config/firewall uci show firewall
uci -q batch <<'EOF' set firewall.defaults=defaults set firewall.defaults.input='DROP' set firewall.defaults.output='ACCEPT' set firewall.defaults.forward='DROP' set firewall.defaults.synflood_protect='1' set firewall.defaults.flow_offloading='0' set firewall.defaults.flow_offloading_hw='0' set firewall.wan=zone set firewall.wan.name='wan' add_list firewall.wan.network='wan' set firewall.wan.input='DROP' set firewall.wan.output='ACCEPT' set firewall.wan.forward='DROP' set firewall.wan.masq='0' set firewall.wan.mtu_fix='0' set firewall.wan_dhcp_renew=rule set firewall.wan_dhcp_renew.name='Allow-DHCP-Renew' set firewall.wan_dhcp_renew.src='wan' set firewall.wan_dhcp_renew.proto='udp' set firewall.wan_dhcp_renew.dest_port='68' set firewall.wan_dhcp_renew.family='ipv4' set firewall.wan_dhcp_renew.target='ACCEPT' set firewall.wan_ping=rule set firewall.wan_ping.name='Allow-Ping' set firewall.wan_ping.src='wan' set firewall.wan_ping.proto='icmp' set firewall.wan_ping.icmp_type='echo-request' set firewall.wan_ping.family='ipv4' set firewall.wan_ping.target='ACCEPT' set firewall.wan_dhcpv6=rule set firewall.wan_dhcpv6.name='Allow-DHCPv6' set firewall.wan_dhcpv6.src='wan' set firewall.wan_dhcpv6.proto='udp' set firewall.wan_dhcpv6.dest_port='546' set firewall.wan_dhcpv6.family='ipv6' set firewall.wan_dhcpv6.target='ACCEPT' set firewall.wan_icmp6=rule set firewall.wan_icmp6.name='Allow-ICMPv6' set firewall.wan_icmp6.src='wan' set firewall.wan_icmp6.proto='icmp' set firewall.wan_icmp6.family='ipv6' set firewall.wan_icmp6.target='ACCEPT' set firewall.wan_ssh=rule set firewall.wan_ssh.name='Allow-SSH-from-WAN' set firewall.wan_ssh.src='wan' set firewall.wan_ssh.proto='tcp' set firewall.wan_ssh.dest_port='22' set firewall.wan_ssh.target='ACCEPT' set firewall.wan_https=rule set firewall.wan_https.name='Allow-HTTPS-from-WAN' set firewall.wan_https.src='wan' set firewall.wan_https.proto='tcp' set firewall.wan_https.dest_port='443' set firewall.wan_https.target='ACCEPT' EOF uci commit firewall fw4 check /etc/init.d/firewall restart
ブリッジ用ルールは nftables の table bridge なのでfw4 のライフサイクル(restart/reload)に合わせて 自分で nft をロードする必要がある。
mkdir -p /etc/nft-bridge.d
cat > /etc/nft-bridge.d/br25g-bridge.nft <<'EOF'
table bridge br25g_filter {
chain forward {
type filter hook forward priority 0; policy accept;
#
# 0) 下流 -> 上流 の必須L2ブロードキャスト/マルチキャスト
#
# IPv4 DHCP 等: L2ブロードキャスト
iifname "eth3" oifname "eth2" ether daddr ff:ff:ff:ff:ff:ff counter accept comment "ALLOW downstream broadcast (DHCPv4 etc)"
# IPv6: all-nodes / all-routers / DHCPv6 multicast
iifname "eth3" oifname "eth2" ether daddr 33:33:00:00:00:01 counter accept comment "ALLOW IPv6 multicast all-nodes"
iifname "eth3" oifname "eth2" ether daddr 33:33:00:00:00:02 counter accept comment "ALLOW IPv6 multicast all-routers"
iifname "eth3" oifname "eth2" ether daddr 33:33:00:01:00:02 counter accept comment "ALLOW DHCPv6 multicast (ff02::1:2)"
# IPv6: solicited-node multicast (33:33:ff:xx:xx:xx) をマスクで許可
iifname "eth3" oifname "eth2" ether daddr & ff:ff:ff:00:00:00 == 33:33:ff:00:00:00 counter accept comment "ALLOW IPv6 solicited-node multicast (ND)"
#
# 1) 同一L2維持に必須(従来どおり)
#
ether type arp counter accept comment "ALLOW ARP"
ether type ip6 ip6 nexthdr icmpv6 icmpv6 type {133,134,135,136} counter accept comment "ALLOW ICMPv6 ND/RA (parsed)"
# DHCPv4/DHCPv6(パースできる場合)
iifname "eth3" oifname "eth2" ether type ip ip protocol udp udp sport 68 udp dport 67 counter accept comment "ALLOW DHCPv4 c->s (parsed)"
iifname "eth2" oifname "eth3" ether type ip ip protocol udp udp sport 67 udp dport 68 counter accept comment "ALLOW DHCPv4 s->c (parsed)"
iifname "eth3" oifname "eth2" ether type ip6 ip6 nexthdr udp udp sport 546 udp dport 547 counter accept comment "ALLOW DHCPv6 c->s (parsed)"
iifname "eth2" oifname "eth3" ether type ip6 ip6 nexthdr udp udp sport 547 udp dport 546 counter accept comment "ALLOW DHCPv6 s->c (parsed)"
#
# 2) 上流 -> 下流 は許可
#
iifname "eth2" oifname "eth3" counter accept comment "ALLOW upstream->downstream"
#
# 3) 下流 -> 上流 は「戻り」+「ルータMAC宛のみ」許可
#
iifname "eth3" oifname "eth2" ct state established,related counter accept comment "ALLOW return traffic (ct est/rel)"
iifname "eth3" oifname "eth2" ether daddr ac:8b:a9:10:db:8f counter accept comment "ALLOW to router MAC only"
#
# 4) それ以外の下流 -> 上流 は遮断
#
iifname "eth3" oifname "eth2" counter drop comment "DROP downstream->upstream (non-router MAC, new)"
}
}
EOF
/etc/firewall.user を “ロード用スクリプト” として用意し、UCI の firewall include に登録して fw4 に管理させる。
cat > /etc/firewall.user <<'EOF' #!/bin/sh nft delete table bridge br25g_filter 2>/dev/null nft -f /etc/nft-bridge.d/br25g-bridge.nft EOF chmod +x /etc/firewall.user uci add firewall include uci set firewall.@include[-1].path='/etc/firewall.user' uci set firewall.@include[-1].type='script' uci set firewall.@include[-1].enabled='1' uci set firewall.@include[-1].fw4_compatible='1' uci commit firewall fw4 check /etc/init.d/firewall restart nft list table bridge br25g_filter
Linux のブリッジはパケットをL2で転送するが、br-netfilter が有効だと ブリッジを通過する IPv4/IPv6 を iptables でも検査する挙動になる。 今回の構成は「ブリッジ通過フレームを table bridge で制御する」方針なのでbr-netfilter を無効化して bridge 側に一本化する。
cat > /etc/sysctl.d/99-bridge-nf.conf <<'EOF' net.bridge.bridge-nf-call-iptables=0 net.bridge.bridge-nf-call-ip6tables=0 net.bridge.bridge-nf-call-arptables=0 EOF /etc/init.d/sysctl restart sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.bridge.bridge-nf-call-arptables 2>/dev/null
不要なサービスを停止
今回の構成ではDHCP/RAサーバー機能は不要なので無効化する。
uci -q delete dhcp.lan uci -q delete dhcp.wan uci commit dhcp /etc/init.d/dnsmasq restart /etc/init.d/odhcpd disable
今回の構成ではSamba機能は不要なので無効化する。
/etc/init.d/samba4 disable
ファイアーウォールの動作確認
# カウンターをリセット nft reset counters table bridge br25g_filter # カウンターを確認 nft -a list chain bridge br25g_filter forward
実際の正常動作時のカウンターの例
root@OpenWrt:~# nft -a list chain bridge br25g_filter forward
table bridge br25g_filter {
chain forward { # handle 1
type filter hook forward priority 0; policy accept;
iifname "eth3" oifname "eth2" ether daddr ff:ff:ff:ff:ff:ff counter packets 11 bytes 2335 accept comment "ALLOW downstream broadcast (DHCPv4 etc)" # handle 2
iifname "eth3" oifname "eth2" ether daddr 33:33:00:00:00:01 counter packets 0 bytes 0 accept comment "ALLOW IPv6 multicast all-nodes" # handle 3
iifname "eth3" oifname "eth2" ether daddr 33:33:00:00:00:02 counter packets 0 bytes 0 accept comment "ALLOW IPv6 multicast all-routers" # handle 4
iifname "eth3" oifname "eth2" ether daddr 33:33:00:01:00:02 counter packets 0 bytes 0 accept comment "ALLOW DHCPv6 multicast (ff02::1:2)" # handle 5
iifname "eth3" oifname "eth2" ether daddr & ff:ff:ff:00:00:00 == 33:33:ff:00:00:00 counter packets 174 bytes 12528 accept comment "ALLOW IPv6 solicited-node multicast (ND)" # handle 6
ether type arp counter packets 7036 bytes 323656 accept comment "ALLOW ARP" # handle 7
ip6 nexthdr ipv6-icmp icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } counter packets 4833 bytes 347768 accept comment "ALLOW ICMPv6 ND/RA (parsed)" # handle 9
iifname "eth3" oifname "eth2" ip protocol udp udp sport 68 udp dport 67 counter packets 0 bytes 0 accept comment "ALLOW DHCPv4 c->s (parsed)" # handle 10
iifname "eth2" oifname "eth3" ip protocol udp udp sport 67 udp dport 68 counter packets 2 bytes 681 accept comment "ALLOW DHCPv4 s->c (parsed)" # handle 11
iifname "eth3" oifname "eth2" ip6 nexthdr udp udp sport 546 udp dport 547 counter packets 0 bytes 0 accept comment "ALLOW DHCPv6 c->s (parsed)" # handle 12
iifname "eth2" oifname "eth3" ip6 nexthdr udp udp sport 547 udp dport 546 counter packets 0 bytes 0 accept comment "ALLOW DHCPv6 s->c (parsed)" # handle 13
iifname "eth2" oifname "eth3" counter packets 37848 bytes 9109894 accept comment "ALLOW upstream->downstream" # handle 14
iifname "eth3" oifname "eth2" ct state established,related counter packets 773 bytes 128154 accept comment "ALLOW return traffic (ct est/rel)" # handle 15
iifname "eth3" oifname "eth2" ether daddr ac:8b:a9:10:db:8f counter packets 86 bytes 5102 accept comment "ALLOW to router MAC only" # handle 16
iifname "eth3" oifname "eth2" counter packets 875 bytes 142058 drop comment "DROP downstream->upstream (non-router MAC, new)" # handle 17
}
}
ベンチマーク
Thread Time(s) Throughput(KB/s) Avg B / Compl
====== ======= ================ =============
0 0.000 0.000 65536.000
1 0.000 0.000 65536.000
2 0.000 0.000 65536.000
3 0.000 0.000 65536.000
##### Totals: #####
Bytes(MEG) realtime(s) Avg Frame Size Throughput(MB/s)
================ =========== ============== ================
15101.437500 100.001 1454.055 151.013
Throughput(Buffers/s) Cycles/Byte Buffers
===================== =========== =============
2416.206 136.706 241623.000
DPCs(count/s) Pkts(num/DPC) Intr(count/s) Pkts(num/intr)
============= ============= =============== ==============
55574.601 0.934 129467.780 0.401
Packets Sent Packets Received Retransmits Errors Avg. CPU %
============ ================ =========== ====== ==========
10890240 5191793 361 69 24.424
パフォーマンスが出ない…と思ったら、ドライバがRSSなどに対応してない。嘘でしょ…
[ 18.279304] r8125 Ethernet controller driver 9.014.01-NAPI loaded
9.014.01-NAPI-RSS のようなRSS対応版が存在するようだ。
同じ事象で困っている人がいた。
https://www.reddit.com/r/OrangePI/comments/1okp321/orange_pi_r2s_subpar_switch_performance/