BGP Flow Specification を RFC8955 とパケットキャプチャから学習してみた

はじめに

この記事は BBSakura Networks Advent Calendar 2023 の 11 日目の記事です。

こんにちは! BBSakura で基盤となるネットワークを開発している酒井です。

私は業務として OCX の基盤となるネットワークの開発や AS2915 の運用に携わっており、普段から BGP を触る機会が多いです。そのなかで BGP Flow Specification (以降は BGP Flow Spec と呼びます)を有効に活用できないかと考えることがありました。

BGP Flow Spec の詳細は後述しますが、端的に言うと BGP でトラフィックフロー情報を送受信することで、トラフィックフロー情報の受信側において動的なパケットフィルタリングや細かいルーティング制御を実現する技術 だと私は考えています。

BGP Flow Spec の活用を考えるにあたっては、まずは知ることから始めようということで BGP Flow Spec について自分なりに調査しました。この記事では、頭の整理もかねてその調査内容をまとめたいと思います。

具体的な調査内容としては、下記の 2 点を行ないました。

  • RFC 8955 を読む
  • BGP Flow Spec のパケットをキャプチャをして内容を眺める

本記事では上記の内容をそれぞれ説明していきます。

RFC 8955

BGP Flow Spec は 2008 年に RFC 5575 が発行されて仕様が決定しました。私が思っていたよりも昔からある技術で少し驚きました。その後、 2020 年に RFC 5575 の内容を改訂する形で RFC 8955 が発行されました。そのため、 RFC 5575 は Obsolete されており、今から学習するのであれば RFC 8955 を読めば OK です。

細かいですが、 RFC 8955 では IPv4 Unicast と VPNv4 の Flow Spec について定義されており、 IPv6 については次の RFC 8956 で定義されています。

さて、内容へと入る前に Flow Spec (Flow Specification)とはそもそも何でしょうか。 Flow Spec とはレイヤー 3 ・ 4 の情報で構成する トラフィックフローをフィルタリングするための情報 になります。この RFC 8955 では BGP を拡張して下記の内容をやり取りするための仕様を定めています。

  • Flow Spec (トラフィックフロー情報)を構成するためのレイヤー 3 ・ 4 のフィルタリングパラメータ (NLRI)
  • Flow Spec に合致するトラフィックフローに対するフィルタリング時のアクション (BGP Extended Community)

つまり、 BGP Flow Spec とは、 特定のトラフィックフローを表現するためのフィルタリング情報とそのトラフィックフローに対するフィルタリング時のアクションを決めて、それを BGP によって動的に伝搬して、伝搬先で当該トラフィックフローに対してフィルタリングアクションを実行すること を目的としています。こういった目的であることから、 BGP Flow Spec の主な応用先として下記の 3 つが RFC 内で挙げられています。

  • Prevention of traffic-based, denial-of-service (DoS) attacks
  • Traffic filtering in the context of BGP/MPLS VPN service
  • Centralized traffic control for SDN/NFV networks

この RFC 8955 が定義している詳しい内容を以降で説明します。

Flow Spec を構成するためのレイヤー 3 ・ 4 のフィルタリングパラメータ

Flow Spec を構成するためのレイヤー 3 ・ 4 のフィルタリングパラメータについては、 RFC 8955 のセクション 4.2.2 で NLRI の Component として定義されています。

Component の具体的な内容として、下記のものが Type 1 ~ 12 として定義されています。

Type Component 値の例 複数値(リスト)の指定可否
Type 1 Destination Prefix 192.0.2.0/24 不可
Type 2 Source Prefix 192.0.2.0/24 不可
Type 3 IP Protocol TCP, UDP, ICMP
Type 4 Port1 22, 443
Type 5 Source Port 22, 443
Type 6 Destination Port 22, 443
Type 7 ICMP Type 0(エコー応答), 8(エコー要求)
Type 8 ICMP Code 0, 1
Type 9 TCP Flags SYN, ACK, FIN
Type 10 Packet Length 500, 1000
Type 11 DSCP 0, 63
Type 12 Fragment DFビット, First Fragment

これらの Type を組み合わせることで、 1 つのフローを定義します。 RFC 内では複数 Type を組み合わせた具体的な例も 4.3 で提示されており参考になります。なお、リストによる複数値の設定が可能な場合は、複数値の間で lt, gt, equal の比較演算子や AND ・ OR の論理演算子を用いて、柔軟な値を設定できます。例として、 RFC の 4.3.2 では Type 4 の Port の値として、 {range [137, 139] or 8080} (ポート番号 137 ~ 139 もしくは 8080)が設定されています。

これだけのパラメータと柔軟性があれば、 L3 ・ L4 のパケットフィルタリングとしてはたいていのユースケースはカバーできるかと思います。

Flow Spec に合致するトラフィックフローに対するフィルタリング時のアクション

フィルタリング時のアクションは BGP Extended Communities によって伝搬されます。 RFC 8955 の セクション 7 で下の表のように BGP Extended Community Type が定義されています。

Community Type action 値の説明
0x8006 traffic-rate-bytes バイト単位での流量制限
0x800c traffic-rate-packets パケット単位での流量制限
0x8007 traffic-action Flow Spec の挙動2
0x8008 rt-redirect AS-2octet 指定のVRFへリダイレクト
0x8108 rt-redirect IPv4 同上
0x8208 rt-redirect AS-4octet 同上
0x8009 traffic-marking 上書き後の DSCP の値

上記以外にも将来的な Type の追加や、ベンダー固有の Type があってもよいと RFC には書かれています。

補足すると、 0x8008・0x8108・0x8208 の末尾の sub-type が 08 となっているものは BGP Extended Community のエンコードフォーマット(後半 6 オクテットの使い方)が異なるだけで、アクションとしては同一となります。

トラフィックレートの制限によって、 DDoS 攻撃への防御や分散ルータへのファイアウォール設定などの使い方ができそうです。なお、トラフィックレートを 0 にすることで該当するすべてのパケットの破棄を指定できます。

また、 VRF へのリダイレクトによりトラフィックフローを曲げることも可能となります。 詳細は割愛しますが、この RFC で定義されている VPNv4 Flow Spec も組み合わせることで、 VPN 間でトラフィックフローをやり取りすることもできそうです。実際に、 Interop 2017Interop 2018 の Shownet ではサービスチェイニングの実現のために Flow Spec が使用されていたようです。

パケットキャプチャ

ここまで RFC 8955 に書かれている仕様について説明してきました。ここからは実際に BGP Flow Spec のパケットをキャプチャして具体的な中身を見ていきましょう。

環境の構築

今回は手軽にパケットキャプチャしたいので、 BGP Update を送信する側として GoBGP、受信側として VyOS を使用します。

GoBGP の Flow Spec 使用方法は GitHub リポジトリ で説明されています。 VyOS の方はまだ Flow Spec についてはちゃんとはドキュメント化されていないようですが Configuration Commands から flowspec で検索をかけると関連する BGP Flow Spec の設定を確認できます。

今回は BGP Flow Spec の Update パケットをキャプチャできればよいので、下の図のように GoBGP と VyOS を一対一で接続するだけの簡単な構成とします。

パケットキャプチャを行なう環境の構成図。左にVyOSを表すルータ、右にGoBGPを表すサーバがある。ルータとサーバは1本の線で結ばれている。サーバ側にはパラメータとして192.168.10.1/24とAS65001、ルータ側には192.168.10.2/24とAS65002が与えられている。サーバ側からルータ側へBGP Updateパケットの送信方向を表す矢印が描かれている。
パケットキャプチャ構成図

GoBGP はバージョン 3.19.0 を使用し、 gobgpd -f <設定ファイル> & で下記の内容の設定ファイルを読み込ませます。

[global.config]
  as = 65001
  router-id = "192.168.100.1"
  local-address-list = "192.168.10.1"

[[neighbors]]
  [neighbors.config]
    peer-as = 65002
    neighbor-address = "192.168.10.2"
    local-as = 65001

    [[neighbors.afi-safis]]
        [neighbors.afi-safis.config]
        afi-safi-name = "ipv4-flowspec"

VyOS はバージョン 1.4 (2023/10/28 時点のローリングリリース)を使用し、下記の内容を設定します。

set interfaces ethernet eth1 address '192.168.10.2/24'
set protocols bgp neighbor 192.168.10.1 address-family ipv4-flowspec soft-reconfiguration inbound
set protocols bgp neighbor 192.168.10.1 remote-as '65001'
set protocols bgp system-as '65002'

設定が正しければ BGP neighbor が Up することを確認できます。

vyos@vyos:~$ show bgp ipv4 flowspec summary
BGP router identifier 192.168.10.2, local AS number 65002 vrf-id 0
BGP table version 0
RIB entries 0, using 0 bytes of memory
Peers 1, using 20 KiB of memory

Neighbor        V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt Desc
192.168.10.1    4      65001         4         4        0    0    0 00:01:12            0        0 N/A

Total number of neighbors 1

この構成で GoBGP から BGP Flow Spec Update パケットを送信します。 VyOS 側ではコマンドによる受信確認とパケットキャプチャを行ない、キャプチャ結果である pcap ファイルを Wireshark で眺めます。(本当は Vyos でパケットフィルタリング時のアクションも見たかったのですが、現時点では受信した Flow Spec を実際のトラフィックにフィルタリング適用する実装は VyOS にはまだ無いようでした)。

パケットキャプチャ結果

Flow Spec の内容を段階的に複雑にしながら見ていきたいと思います。

まずは、単純な内容からスタートします。 Source Prefix のみでフィルタリングを行ない、フィルタリングアクションとしてはトラフィックレートを制限するものを用いてみます。なお、BGP Flow Spec に関わる GoBGP のコマンドは先ほど紹介した GoBGP の Github リポジトリ から確認できます。

GoBGP コマンド: gobgp global rib -a ipv4-flowspec add match source 192.168.200.0/24 then rate-limit 10

上記のコマンドにより GoBGP 側の RIB に登録されたことが見えます。

root@gobgp:/gobgp# gobgp global rib -a ipv4-flowspec
   Network                    Next Hop             AS_PATH              Age        Attrs
*> [source: 192.168.200.0/24] fictitious                                00:00:44   [{Origin: ?} {Extcomms: [rate: 10.000000]}]

また、 VyOS でも当該の BGP Flow Spec Update を正常に受信していそうです。

vyos@vyos:~$ show bgp ipv4 flowspec detail
BGP flowspec entry: (flags 0x418)
        Source Address 192.168.200.0/24
        FS:rate 10.000000
        received for 00:00:11
        not installed in PBR

Displayed  1 flowspec entries

実際に取得した pcap ファイルを Wireshark で見てみます。下の図が BGP Update のパケットの内容になります。 Path attributes -> MP_REACH_NLRI -> NLRI と見ていくと、 FLOW_SPEC_NLRI があり、 Type 2 の Source Prefix 192.168.200.0/24 がエンコードされていることがわかります。

1つ目のBGP UpdateパケットのNLRI部分のWiresharkスクリーンショット。Path attributes、MP_REACH_NLRI 、NLRIと見ていくと、期待通りにFLOW_SPEC_NLRIがあり、Type 2のSource Prefix 192.168.200.0/24 がエンコードされていることがわかる。
1つ目のBGP Update - NLRI

また、下の図の Path attributes -> EXTENDED_COMMUNITIES と見ていくと、 Type 0x8006 (Type 0x80 と Subtype 0x06)の traffic-rate が値 10 でエンコードされていることがわかります。

1つ目のBGP UpdateパケットのBGP Extended Community部分のWiresharkスクリーンショット。Path attributes、EXTENDED_COMMUNITIESと見ていくと、期待通りにType 0x8006 (Type 0x80とSubtype 0x06)のtraffic-rateが値10でエンコードされていることがわかる。
1つ目のBGP Update - BGP Extended Community

問題なく BGP Flow Spec の Update をやり取りできていそうです。

次に、複数のフィルタリング Type を組み合わせることを試してみます。具体的には、フィルタリングパラメータとして Destination Prefix と Destination Port の Type を加えてみます。この時、 Destination Port としては複数の値を比較演算子や論理演算子で表現してみます。

GoBGP コマンド: gobgp global rib -a ipv4-flowspec add match destination 192.168.100.0/24 source 192.168.200.0/24 destination-port '>=100&<=200 ==400' then rate-limit 10

下のこの BGP Update のパケットキャプチャの図を見ると、 Destination Prefix 192.168.100.0/24 と Destination Port が追加されています。また、 Destination Port は (>=100 && <=200 || =400) というように期待通りに複数の値を組み合わせたものとなっていそうです。

2つ目のBGP UpdateパケットのNLRI部分のWiresharkスクリーンショット。期待通りにDestination Prefix 192.168.100.0/24とDestination Portが追加されていることがわかる。また、Destination Portはコマンドで指定した通り、ポート番号100から200、または、400という複数の値から比較演算子や論理演算子で表現した形通りにエンコードされている。
2つ目のBGP Update - NLRI

最後に、ビットマップ形式のフィルタリングパラメータである Type 9 の TCP Flags をフィルタリングに追加し、アクションとしては RT Redirect を用いてみます。

GoBGP コマンド: gobgp global rib -a ipv4-flowspec add match destination 192.168.100.0/24 source 192.168.200.0/24 destination-port '>=100&<=200 ==400' tcp-flags SA then redirect 65003:65003

NLRI を見てみると、TCP Flags フィルタリングとして SYN と ACK がセットされていることがわかります。それ以外のフラグは Not set となっているので期待通りです。

3つ目のBGP UpdateパケットのNLRI部分のWiresharkスクリーンショット。NLRIを見てみると、期待通りにTCP FlagsフィルタリングとしてSYNとACKがセットされていることがわかる。
3つ目のBGP Update - NLRI

また、フィルタリングアクションとして RT Redirect が問題なくエンコードされています。 (type 0x80: 2-octet AS, 4-octet value) の形式でコマンドの redirect 部分を指定したので、 Type が 0x8008 になっています。

3つ目のBGP UpdateパケットのBGP Extended Community部分のWiresharkスクリーンショット。EXTENDED_COMMUNITIESを見ていくと、期待通りにRedirectのアクションがType 0x8008形式でエンコードされていることがわかる。
3つ目のBGP Update - BGP Extended Community

以上となります。全然問題なく BGP Flow Spec Update パケットを確認でき、 GoBGP ありがたいと感じました。

おわりに

今回の記事では RFC 8955 やパケットキャプチャを通して行なった BGP Flow Spec の調査の内容について書きました。

記事の途中で書いた通り、 Flow Spec 自体は 2008 年に RFC が発行された技術ですので、今更感がある内容だったかもしれませんが参考になれば幸いです。 RFC 8955 には今回説明していない Validation 3などの内容もあったのですが、記事が長くなりそうでしたのスキップしました。詳細を確認したい方はぜひ RFC 8955 を読んでいただければと思います。

もし、今回の記事を通して BBSakura Networks という会社に興味を持たれた方がいましたら、会社ホームページの 採用情報 をご確認ください。ネットワークで面白いことがしたい人にはオススメの会社かと思うので、お気軽にお問い合わせください。

明日以降も BBSakura Networks Advent Calendar 2023 は続きますので、楽しみにお待ちください。


  1. Type 4 の Port は送信元ポート・宛先ポートのどちらにも適用されます。
  2. 複数の Flow Spec が存在していた場合に、 1 つの Flow Spec 条件と合致した時に後続の Flow Spec も評価を行なうかどうかを指定できる。また、トラフィックのサンプリングやログ取得の ON / OFF を指定できる。詳細は 7.3 を参照してください。
  3. Validation については RFC 9117 でリバイズされています。