RFC5575で標準化されたBGP Flowspecは、当初からDDoS攻撃ミティゲーションへのアプリケーションが想定されていましたが、現状はごく一部のサービス事業者しか対応していないのではないでしょうか。そういう当社でも現時点では全く対応できていません。理由は、当社のバックボーン機器がFlowspecに対応していないからです。
とはいえ、そもそも当社のバックボーン帯域で捌ききれない流量の攻撃が発生したら、Flowspecに限らずどのような手法でも当社サービス網内だけではフィルタしきれません。そのようなケースでは上流トランジット事業者(以降トランジットSP)の網内でフィルタするためにRTBH経路を広報します。当社のトランジットSP各社とも、特定のコミュニティ属性を付与した経路を受信して、RTBHを有効にしてくれるので、有事には活用させていただいてるわけです。(多謝)
でも最近、ん??と思ったのですが、もしもトランジットSPがFlowspec経路も受信してくれたら、攻撃を受けているホストへ向かう全てのパケットをブラックホールするかわりに、攻撃パケットだけをフィルタできるわけですから、今よりも格段にうれしくなります。

いつかそんな日がくることを期待して、まずは仮想ルータでPoCしてみましたので、本稿に纏めました。

テスト構成

poc_flowspec

 

AS3を当社に、AS2をトランジットSPにそれぞれ見立ててます。AS3のルータ3sは、Flowspec経路を生成してAS2のルータ2aに広報させてもらいます。2aは、3sから受信した経路を自AS内のルータ2bと2cに広報し、2bと2cはフィルタを有効にします。このフィルタによって、AS1からAS3のホスト10.0.3.11へ向かうDDoSパケットをAS2でドロップする、というシナリオです。

今回の検証とは関連のない部分も含めて、全ルータのコンフィグを本稿の末尾にマルっと添付しておきます。ほとんどすべて仮想ルータで、PC1台でも動作確認できます。興味ある方はためしてみてください。ただし、フロー経路からインストールするフィルタを実際に有効にできる仮想ルータが手元になかったため、2bだけはJuniper MX5を使いました。また、3sはGoBGPdを使って経路生成しました。

フロー経路を生成する

AS3のホスト10.0.3.11宛にDNSリフレクション攻撃が流入してきたという想定で、gobgpのCLIを使ってルータ3sで以下のフロー経路を生成します。

※下記ルータコンフィグの詳細については記事末尾のリンクよりご覧いただけます。

  1. 10.0.3.11宛UDPソースポート53パケットを破棄
  2. 10.0.3.11宛UDPフラグメントパケットを破棄
  3. ただし、ソースアドレス10.1.0.0/30からのパケットはすべて通す
gobgp global rib -a ipv4-flowspec add match destination 10.0.3.11/32 source 10.1.0.0/30 protocol udp source-port '=53' then accept origin igp
gobgp global rib -a ipv4-flowspec add match destination 10.0.3.11/32 source 10.1.0.0/30 protocol udp fragment is-fragment then accept origin igp
gobgp global rib -a ipv4-flowspec add match destination 10.0.3.11/32 protocol udp source-port '=53' then discard origin igp
gobgp global rib -a ipv4-flowspec add match destination 10.0.3.11/32 protocol udp fragment is-fragment then discard origin igp

生成した経路の到達を確認していきます。まず、3sで2aへの広報経路を確認します:

gobgp nei 10.0.2.1 adj-out -a ipv4-flowspec
    Network                                                                         Next Hop             AS_PATH              Attrs
    [destination:10.0.3.11/32][source:10.1.0.0/30][protocol: =udp][source-port: =53]fictitious           3                    [{Origin: i}]
    [destination:10.0.3.11/32][source:10.1.0.0/30][protocol: =udp][fragment: is-fragment]fictitious           3                    [{Origin: i}]
    [destination:10.0.3.11/32][protocol: =udp][source-port: =53]fictitious           3                    [{Origin: i} {Extcomms: [discard]}]
    [destination:10.0.3.11/32][protocol: =udp][fragment: is-fragment]fictitious           3                    [{Origin: i} {Extcomms: [discard]}]

つぎに2aで3sからのフロー経路受信を確認します:

admin@vSRX2a> show route table inetflow.0

inetflow.0: 4 destinations, 4 routes (4 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

10.0.3.11,10.1.0.0/30,proto=17,srcport=53/term:1
                   *[BGP/170] 00:02:09, localpref 100, from 10.0.3.9
                      AS path: 3 I
                      Fictitious
10.0.3.11,10.1.0.0/30,proto=17,frag:02/term:2
                   *[BGP/170] 00:01:54, localpref 100, from 10.0.3.9
                      AS path: 3 I
                      Fictitious
10.0.3.11,*,proto=17,srcport=53/term:3
                   *[BGP/170] 00:01:54, localpref 100, from 10.0.3.9
                      AS path: 3 I
                      Fictitious
10.0.3.11,*,proto=17,frag:02/term:4
                   *[BGP/170] 00:01:54, localpref 100, from 10.0.3.9
                      AS path: 3 I
                      Fictitious

引き続き、2bで2aからのフロー経路受信を確認します:

admin@MX5T-51> show route table inetflow.0

inetflow.0: 4 destinations, 4 routes (4 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

10.0.3.11,10.1.0.0/30,proto=17,srcport=53/term:1
                   *[BGP/170] 00:03:21, localpref 100, from 10.0.2.1
                      AS path: 3 I, validation-state: unverified
                      Fictitious
10.0.3.11,10.1.0.0/30,proto=17,frag:02/term:2
                   *[BGP/170] 00:03:06, localpref 100, from 10.0.2.1
                      AS path: 3 I, validation-state: unverified
                      Fictitious
10.0.3.11,*,proto=17,srcport=53/term:3
                   *[BGP/170] 00:03:05, localpref 100, from 10.0.2.1
                      AS path: 3 I, validation-state: unverified
                      Fictitious
10.0.3.11,*,proto=17,frag:02/term:4
                   *[BGP/170] 00:03:05, localpref 100, from 10.0.2.1
                      AS path: 3 I, validation-state: unverified
                      Fictitious

DNSリフレクション攻撃を疑似生成してみる

AS1のルータ1aへ、10.0.3.11宛の攻撃パケットを流し込んでみます。送信元アドレスを

  0x0a, 0x01, 0x00, drnd(1),

とすることで第4オクテットをランダムにしてます。10.1.0.0/30からのパケットを許可するフローにマッチするパケットを確認するためです。

ルータ1aのコンフィグは割愛しますが、AS3へ向かうトラフィックは1b→2bを経由します。2bでFlowspecからインストールされたフィルタのマッチカウントをみると、

admin@MX5T-51> show firewall filter __flowspec_default_inet__

Filter: __flowspec_default_inet__
Counters:
Name                                                Bytes              Packets
10.0.3.11,*,proto=17,frag:02                     21296608                54054
10.0.3.11,*,proto=17,srcport=53                  19613616                13508
10.0.3.11,10.1.0.0/30,proto=17,frag:02               329264                  834
10.0.3.11,10.1.0.0/30,proto=17,srcport=53               310728                  214

というかんじで、想定通りに動作していることが確認できます。

トランジットSPのセキュリティ対策について

構成的に、AS2のルータ2aでは所謂Flowspecバリデーションを無効にしておかないと厳しいのですが、不正な経路の受信やリソースの枯渇を防ぐことができないと、サービス提供は期待できません。上記の2aのコンフィグでは、以下を実現できています。

  • ピアセッションのMD5認証
admin@vSRX2a# run show bgp neighbor 10.0.3.9 | match auth
Options: <Multihop Preference LocalAddress AuthKey Ttl AddressFamily PeerAS PrefixLimit LocalAS Refresh>
Authentication key is configured
  • プレフィクスフィルタ

ルータ3sから、許可されていない10.0.4.11/32を広報してもインストールされないことが確認できます:

admin@vSRX2a# run show route receive-protocol bgp 10.0.3.9 hidden table inetflow.0 detail

inetflow.0: 7 destinations, 7 routes (6 active, 0 holddown, 1 hidden)
  10.0.4.11,*,proto=6/term:N/A (1 entry, 0 announced)
     Nexthop: Self
     AS path: 3 I
     Communities: traffic-rate:0:0
  • 受信プレフィクス数の上限設定

上限を超えるとセッションをシャットダウンすることが確認できます:

Oct 13 18:30:19 vSRX2a rpd[1085]: 10.0.3.9 (External AS 3): Configured maximum prefix-limit threshold(16) exceeded for inet-flow nlri: 17
...
Oct 13 18:36:19 vSRX2a rpd[1085]: 10.0.3.9 (External AS 3): Configured maximum prefix-limit threshold(16) exceeded for inet-flow nlri: 20
Oct 13 18:36:29 vSRX2a rpd[1085]: 10.0.3.9 (External AS 3): Shutting down peer due to exceeding configured maximum prefix-limit(20) for inet-flow nlri: 21
Oct 13 18:36:29 vSRX2a rpd[1085]: bgp_rt_maxprefixes_check_common:7429: NOTIFICATION sent to 10.0.3.9 (External AS 3): code 6 (Cease) subcode 1 (Maximum Number of Prefixes Reached) AFI: 1 SAFI: 133 prefix limit 20
Oct 13 18:36:29 vSRX2a rpd[1085]: Received BAD update from 10.0.3.9 (External AS 3), family inet-flow(8192), prefix 10.0.3.35,*,proto=6/72

リダイレクトアクションのフロー経路を拒否できない?

BGP Flowspecのフィルタリングアクションとしては、デフォルト(accept)以外の以下が定義されています:

+--------+--------------------+--------------------------+
| type   | extended community | encoding                 |
+--------+--------------------+--------------------------+
| 0x8006 | traffic-rate       | 2-byte as#, 4-byte float |
| 0x8007 | traffic-action     | bitmask                  |
| 0x8008 | redirect           | 6-byte Route Target      |
| 0x8009 | traffic-marking    | DSCP value               |
+--------+--------------------+--------------------------+

上記の例ではこのうち0x8006を使ってドロップしていますが、トランジットASの立場では、その他のアクションは許可したくないはずです。とくに不正なリダイレクトアクションのフロー経路を広報されては困ります。

しかしテスト環境では、Flowspecのアクションでマッチするポリシーを有効にすることができませんでした。本当に実現できないということであれば、ぜひともベンダーによる今後の実装に期待したいところです。

まとめ

というわけで、BGP Flowspec経路の受信サービスがトランジットSPから提供されたら、という勝手な想定で、いろいろ試してみました。実現に向けては、SP各社にがんばっていただくだけでなく、デバイスの機能面での向上も求めらることになりそうです。ついでに実現してほしい機能としては、トランジットSP側でフロー経路からインストールされたフィルタのカウンタを、コチラ側から取得できるとさらに嬉しいですね。BGP Flowspecは次のバージョンのドラフトも公開されて更に発展しそうです。最後になりましたが、うれしいことに当社の若手エンジニアが実際に業界各社に働きかけていくことを宣言してくれました。今後の動向に乞うご期待です。

参考リンク

  1. IRS25 DDoS対策あれこれ
  2. NANOG63 DDoS Mitigation Using BGP Flowspec
  3. ルータコンフィグ: 1a, 1b, 1c, 2a, 2b, 2c, 3a, 3b, 3c, 3s