
2026/02/08 23:02
**ご自身のAS(自治システム)を運用する方法:FreeBSD 上で FRR を使い BGP、GRE トンネル、およびポリシールーティングを設定する**
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
主なメッセージ:
個人は、AS番号(例:AS201379)とIPv6プレフィックス(2a06:9801:1c::/48)をスポンサーとなるローカルインターネットレジストリから取得し、FreeBSD+FRRouting などの比較的手頃なハードウェアで運用することで、パブリックインターネット上に完全機能の自律システム(Autonomous System)を稼働させることができます。
主要技術詳細:
- ルーターは FreeBSD 上で FRR を動かし、GRE トンネルで 2 つのアップストリームプロバイダー(iFog AS34927 と Lagrange AS209735)へ接続し、GIF(IPv6‑in‑IPv4)トンネルを使用してダウンストリームサーバーと通信します。
- /48 のブラックホールルートにより、未経路化のトラフィックが排除されます。
- アウトバウンド BGP 発表はルートマップで整形され、iFog へのピアにはコミュニティ 34927:9501/9301 が付与され、Lagrange へは AS‑path の prepending を適用してインバウンドトラフィックを iFog 側に誘導します。
- インバウンドルートは大規模なボゴンリスト(PL‑BOGONS)でフィルタリングされ、/48 までのプレフィックスに対する最終的な許可が設定されます。
- PF ファイアウォールは制御平面(SSH, BGP)を分離し、BGP ピア数を制限し、アンチスプーフィングを強化し、トンネルごとに MSS をクランプします。
ダウンストリーム VPS 設定:
- デュアル FIB ポリシールーティング:プロバイダー経路はデフォルトルートで FIB 0 を使用し、BGP トラフィックには GIF トンネルを備えた FIB 1 を使用します。
- PF ルールは
とrtable 1
を利用して正しいパスリングを保証し、GIF トンネルはreply-to
(トンネルインターフェース)とfib 1
(外部 IPv4 カプセル化)の両方で設定されます。tunnelfib 0
検証:
- テストとして、jails からプロバイダーおよび BGP アドレスへ curl を実行し、mtr traceroute により GRE, GIF および BGP プレフィックスを経由するホップが確認できました。
得られた教訓と今後の作業:
- トンネルに対する必須 MSS クランプ;FreeBSD のマルチ FIB が Linux MARK ハックより有効であること;PF
が非対称ルーティングに効果的であること;冗長性とトラフィックエンジニアリングのためのデュアルアップストリームの価値。reply-to - 今後は、さらなるトンネル処理の改善、多用途 FIB の拡張、および追加のアップストリームピアへの拡大を計画しています。
影響:
この実装は、比較的手頃なハードウェアでプロバイダーに依存しないアドレッシングと本格的な BGP ピアリングが可能であることを示し、BGP への実験を促進し、オペレーターのボゴンフィルタリングやトンネル管理への慣行に影響を与え、研究者やニッチサービスプロバイダー向けの低コストモデルを提供します。
本文
インターネット上で自分自身の Autonomous System(AS)を運用する――というと、ISPや大企業向けに限られたことだと思われがちです。実際にはそうではありません。LIR(ローカルインターネットレジストリ)が個人にも AS 番号と IPv6 プレフィックスを提供し、FreeBSD が BGP ルーティングツールを備えているため、単一の仮想マシンから Default‑Free Zone に自分のアドレス空間を宣言できます。
この記事では、RIPE を通じてスポンサー LIR からリソースを取得し、FRR を使った FreeBSD BGP ルーターの設定、GRE/GIF トンネルでプレフィックスを遠隔サーバへ分配する構築方法、および異なる IPv6 アドレス空間を同時に使用する際に発生する経路課題の解決策までを詳述します。
アドレスについて
本文中のプロバイダー割り当て IP、ホスト名、管理用 IP はすべて RFC 5737 / RFC 3849 のドキュメント範囲に置き換えられています。
私自身の AS 番号(AS201379)とプレフィックス(2a06:9801:1c::/48)は公開 BGP リソースとしてそのまま表示されています。上流 AS 番号(AS34927、AS209735)も同様に公衆ルーティングテーブルで確認できます。
なぜ自分の AS を運用するか?
プロバイダー割り当て IPv6 はそのプロバイダーに縛られます。別のホスティングへ移行するとアドレスが変わり、DNS レコードやファイアウォールルール、評判、そしてそれを参照しているすべてのシステムが影響を受けます。
自分の AS とプレフィックスを持つことで、アドレスはあなたとともに移動します。サーバーを移転しトンネルエンドポイントを更新するだけで、サービス構成を一切触らずにトラフィックが再び流れます。
その他の実務上のメリットとして、BGP を理解するとインターネット経路についての考え方が変わります。DFZ(Default‑Free Zone)で自分のプレフィックスが拡散し、世界中のルックアップグラスに表示される様子を確認できるのは非常に満足感があります。また複数プロバイダーでサービスを展開する場合、プロバイダーに依存しないアドレッシングは設計を大幅に簡素化します。
リソース取得
インターネット上でプレフィックスを宣言するには、地域インターネットレジストリ(欧州では RIPE NCC)から次の二つが必要です:
- AS 番号 – BGP 上での識別子。私の場合は AS201379。
- IPv6 プレフィックス – 宣言するアドレス空間。私は 2a06:9801:1c::/48 を取得しました。
個人が RIPE のメンバーになる必要はありません(費用や手続きが発生します)。代わりに、スポンサー LIR(既存の RIPE メンバー)がリソース登録を後押しします。ハイパーオペレーター向けにサービスを提供する LIR がいくつかあります。プロセスは一般的に次のようになります:
- 目的と使用ケースを書いた申請フォームを提出
- RIPE データベースオブジェクト(aut-num、inet6num、route6)を作成
- RPKI ROA(Route Origin Authorizations)でプレフィックスと AS を暗号的に結び付け
書類が完了したら、上流接続が必要です。BGP セッションを受け入れ、インターネット全体へルートを発信してくれる人(あるいは組織)が必要になります。
アーキテクチャ概要
セットアップは二階層構成です:上流プロバイダーとピアリングする BGP ルーター、そしてその /48 からトンネルで受け取る下流サーバー。図のように表現できます。
┌──────────────────────────────┐ │ Default‑Free Zone │ └───────┬──────────────┬──────┘ │ │ AS34927 (iFog) AS209735 (Lagrange) │ │ GRE tunnel Direct peering │ │ ┌─────────┴──────────────┴──────┐ │ router01 (BGP Router) │ │ FreeBSD + FRR │ │ AS201379 │ │ 2a06:9801:1c::/48 │ └─────┬───────────────────────┬───┘ │ │ GIF tunnel GIF tunnel (proto 41) (proto 41) │ │ ┌────────────┴─────┐ ┌───────┴───────────┐ │ vps01 │ │ dcgw01 │ │ VPS │ │ DC OPNsense │ │ :1000:: │ │ :2000::/62 │ │ /64 │ │ │ └─────────────────┘ └──────────────────┘
BGP ルーター(
router01)は二つの上流プロバイダーへ /48 を宣言し、アグリゲート用にブラックホール経路を保持します。個別の /64(VPS 用)や /62(データセンタ用)は GIF トンネルで下流サーバへ送られます。各サーバは自前のプロバイダー割り当て IPv6 を維持しつつ、GIF で渡される実際にグローバル経路化されたアドレスを利用できます。
BGP ルーター
このルーターはコロケーション施設内の FreeBSD VM 上で稼働し、二つの上流ネットワークへ直接接続されています。以下は
/etc/rc.conf の主要部分です:
hostname="router01" # セキュリティ kern_securelevel_enable="YES" kern_securelevel="2" # 物理インターフェース ifconfig_vtnet0="inet 198.51.100.10/24 -rxcsum -txcsum -rxcsum6 -txcsum6 -lro -tso" ifconfig_vtnet0_ipv6="inet6 2001:db8:100::96/64" defaultrouter="198.51.100.1" ipv6_defaultrouter="2001:db8:100::1" # 発信プレフィックス用ループバック ifconfig_lo0_alias0="inet6 2a06:9801:1c::1 prefixlen 64" # トンネルインターフェース cloned_interfaces="gif0 gif1 gre0" kld_list="if_gif if_gre" # GRE トンネル(iFog) ifconfig_gre0="tunnel 198.51.100.10 198.51.100.44" ifconfig_gre0_ipv6="inet6 2001:db8:300::2 2001:db8:300::1 prefixlen 128" ifconfig_gre0_descr="Transit-iFog" # GIF トンネル(VPS) ifconfig_gif0="tunnel 198.51.100.10 203.0.113.10" ifconfig_gif0_ipv6="inet6 2a06:9801:1c:ffff::1 2a06:9801:1c:ffff::2 prefixlen 128" ifconfig_gif0_descr="Tunnel-to-VPS" ipv6_route_cloud="2a06:9801:1c:1000::/64 2a06:9801:1c:ffff::2" # GIF トンネル(データセンタ) ifconfig_gif1="tunnel 198.51.100.10 192.0.2.50" ifconfig_gif1_ipv6="inet6 2a06:9801:1c:ffff::3 2a06:9801:1c:ffff::4 prefixlen 128" ifconfig_gif1_descr="Tunnel-to-Datacenter" ipv6_route_dc="2a06:9801:1c:2000::/62 2a06:9801:1c:ffff::4" # ブラックホール経路 ipv6_static_routes="myblock cloud dc" ipv6_route_myblock="2a06:9801:1c::/48 -reject" ipv6_gateway_enable="YES" # サービス pf_enable="YES" pflog_enable="YES" frr_enable="YES" zfs_enable="YES" sshd_enable="YES"
重要ポイント
- ブラックホール経路 (
) は未割り当てサブネットへのトラフィックが上流に戻るのを防ぎます。-reject - 点対点トンネルアドレス は /128 を使用し、
のリンクサブネット内でペアを割り当てています。2a06:9801:1c:ffff::/64 - 下流ルート は各トンネル先に特定のサブネット(VPS 用 /64、データセンタ用 /62)を設定しています。
- GRE vs GIF:iFog では GRE が必要ですが、下流トンネルは GIF(プロトコル 41、IPv6‑in‑IPv4)がシンプルです。
FRR 設定
FRR は BGP セッションを処理します。
/usr/local/etc/frr/frr.conf の抜粋です:
frr version 10.5.1 frr defaults traditional hostname router01 log syslog informational service integrated-vtysh-config ! ipv6 prefix-list PL-MY-NET seq 5 permit 2a06:9801:1c::/48 ! ipv6 prefix-list PL-BOGONS seq 5 deny ::/0 le 7 ... ipv6 prefix-list PL-BOGONS seq 100 deny 2a06:9801:1c::/48 ipv6 prefix-list PL-BOGONS seq 105 deny ::/0 ge 49 ipv6 prefix-list PL-BOGONS seq 110 permit ::/0 le 48 ! route-map RM-IFOG-OUT permit 10 match ipv6 address prefix-list PL-MY-NET set community 34927:9501 34927:9301 additive exit ! route-map RM-LAGRANGE-OUT permit 10 match ipv6 address prefix-list PL-MY-NET set as-path prepend 201379 201379 exit ... ipv6 route 2a06:9801:1c::/48 blackhole ! router bgp 201379 bgp router-id 198.51.100.10 no bgp default ipv4-unicast neighbor 2001:db8:300::1 remote-as 34927 ...
設計上の決定
- プレフィックスリスト
は自前 /48 のみを対象。アウトバウンド・ルートマップで宣言する際に使用。PL-MY-NET
は bogon フィルタ(リンクローカル、ULA、マルチキャスト、ドキュメント範囲等)と自前プレフィックスの除外、および /48 より具体的//8 より広いアドレスをブロック。PL-BOGONS
- ルートマップ
- iFog へのアウトバウンド (
):/48 を BGP コミュニティで制御し、経路の拡散を管理。RM-IFOG-OUT - Lagrange へのアウトバウンド (
):AS‑パスを prepend して iFog へトラフィックを誘導。RM-LAGRANGE-OUT - インバウンド では bogon フィルタを適用。
- iFog へのアウトバウンド (
- BGP セッション詳細(例:
、ttl-security hops 1
)はルートリーク対策と安定性確保に寄与。soft-reconfiguration inbound
ルーターのファイアウォール
PF 設定で制御平面(SSH, BGP)とデータ平面(転送トラフィック)を分離します。主なマクロと規則は次のようになります:
# --- マクロ --- ext_if = "vtnet0" dc_tun = "gif1" vps_tun = "gif0" trusted_ipv4 = "{ 198.51.100.100, 198.51.100.101 }" trusted_ipv6 = "{ 2001:db8:ffff:1::/64, 2001:db8:ffff:2::/64 }" bgp_peers_v4 = "{ 198.51.100.20 }" bgp_peers_v6 = "{ 2001:db8:100::ff }" ifog_gre_endpoint = "198.51.100.44" ifog_bgp_peer = "2001:db8:300::1" my_network_v6 = "2a06:9801:1c::/48" vps_v4 = "203.0.113.10" ... # --- 制御平面 --- pass in quick on $ext_if proto tcp from <bgp_peers_v6> to ($ext_if) port 179 flags S/SA keep state pass in quick on $ext_if proto gre from $ifog_gre_endpoint to ($ext_if) ... # --- データ平面 --- pass in quick on $vps_tun inet6 from any to $my_network_v6 keep state pass in quick on $dc_tun inet6 from any to $my_network_v6 keep state pass out quick all keep state
下流への返信トラフィックは
reply-to ディレクティブで同じトンネル経路をたどるようにします。
下流サーバ:デュアル FIB とポリシールーティング
VPS(
vps01) にはプロバイダー割り当て IPv6(2001:db8:200:0:1000::/68)と自前 BGP IPv6(2a06:9801:1c:1000::/64)が存在します。さらにプライベート IPv4(10.254.254.0/24)は NAT でホストのパブリック IPv4 にマッピングされています。
ジャイルが BGP アドレスを使用して通信する際は GIF トンネル経由で
router01 へ出ていく必要があります。プロバイダーアドレスの場合は通常ルートに従います。この課題は デュアル FIB ポリシールーティング(FreeBSD の複数ルーティングテーブル)で解決します。
デュアル FIB の構成
| FIB | デフォルト経路 | 使用者 |
|---|---|---|
| 0 | vtnet0 → VPS プロバイダー upstream | ホストトラフィック、プロバイダーアドレスジャイル |
| 1 | gif0 → BGP ルーター () | BGP アドレスジャイル(2a06:…/48) |
GIF トンネルインターフェースは FIB 1 に割り当て、外部 IPv4 エンキャプセレーションは FIB 0 を使用します。これにより、IPv4 層がプロバイダーのデフォルトルートで送信され、再帰的ループを防げます。
FIB 1 の静的ルート例:
route_fib1default="-6 default -interface gif0 -fib 1" route_jailleak="-6 2001:db8:200:0:1000::/68 -interface bastille0 -fib 1" route_bgplink="-6 2a06:9801:1c:1000::/64 -interface bastille0 -fib 1"
PF 規則
# BGP アドレスジャイル → FIB 1(gif0)へ強制 pass in quick on bastille0 inet6 from $bgp_net to any rtable 1 keep state
rtable 1 ディレクティブは PF にマッチしたパケットを FIB 1 でルーティングさせます。FIB 1 のデフォルト経路が GIF を通るため、パケットは router01 へトンネル化され送信されます。
返信トラフィックには
reply-to が必要です:
pass in quick on $tun_if reply-to ($tun_if $bgp_hub_ip) inet6 from any to $bgp_net keep state
これがないと、カーネルは FIB 0 を参照し、戻りパケットが
vtnet0 から送信されてプロバイダーによりスプーフィングでドロップされます。
動作確認
ジャイル内で両方のアドレスを使ったテスト:
# プロバイダーアドレス(NAT 経由) curl --interface 2001:db8:200:0:1000::10 https://ifconfig.co 2001:db8:200::2 # BGP アドレス(トンネル経由) curl --interface 2a06:9801:1c:1000::10 https://ifconfig.co 2a06:9801:1c:1000::10
外部ホストからの traceroute で BGP パスが確認できます:
$ mtr -rw 2a06:9801:1c:1000::10 ... 12.|-- 2a06:9801:1c:ffff::2 0.0% 10 72.7 98.9 68.8 198.8 42.4 13.|-- 2a06:9801:1c:1000::10 0.0% 10 164.1 83.1 63.5 164.1 33.4
途中で iFog のトランジット、
router01 への GRE トンネル、GIF トンネルを経て vps01 に到達することが確認できます。
学んだこと
- MSS クランプ は必須。トンネルは MTU を減らすため、各層でクランプしないとパケットが失われます。
- FIB 分離 はソースベースのルーティングよりもシンプルで堅牢です。FreeBSD のマルチ FIB が完全な制御を提供します。
- Bogon フィルタ は小規模ネットワークでも重要。誤ったまたは悪意ある経路が侵入しないようにします。
- reply-to は非対称ルーティング解決策。到着インターフェースと返信先を明示することで、正しいパスで戻ります。
- 二つの上流 で冗長性とトラフィックエンジニアリングが可能です。単一上流だとフェイルオーバーは不十分。
結論
インターネット上に自分自身の AS を運用することは、多くの人が想像するほどハードルが高いわけではありません。技術的な難しさはなく、FreeBSD VM、FRR、数本のトンネルと注意深い PF ルールでプロバイダーに依存しないアドレッシングを実現できます。
下流サーバでのデュアル FIB アプローチが最も満足感があります。BGP トラフィックは GIF を通り、プロバイダーアドレスはデフォルトルートを使用。PF の
rtable ディレクティブで純粋にソースアドレスに基づいて振る舞いを分岐させるだけです。
ブログ記事としてはオーバーかもしれませんが、私が運用しているすべてのサービスに共通するインフラストラクチャです。プロバイダー移行時にアドレスが残ることで運用が大幅に簡素化され、AS 番号をトレーサウトで確認できるという満足感は格別です。