Comments
Description
Transcript
修士論文 LISPにおける二段階マップテーブルを用いたDDoS 攻撃緩和
NAIST-IS-MT1151050 修士論文 LISP における二段階マップテーブルを用いた DDoS 攻撃緩和方式の提案 齋藤 利文 2013 年 2 月 7 日 奈良先端科学技術大学院大学 情報科学研究科 情報処理学専攻 本論文は奈良先端科学技術大学院大学情報科学研究科に 修士 (工学) 授与の要件として提出した修士論文である。 齋藤 利文 審査委員: 山口 英 教授 (主指導教員) 藤川 和利 教授 (副指導教員) 門林 雄基 准教授 (副指導教員) LISP における二段階マップテーブルを用いた DDoS 攻撃緩和方式の提案∗ 齋藤 利文 内容梗概 DDoS 攻撃は深刻な脅威であるが,現在一般的に実施されている DDoS 攻撃対 策は,標的サーバーまでの経路上の負荷については考慮していない,意図的もし くは誤って攻撃の意図のないパケットを破棄してしまうことがある,DDoS 攻撃 対処について攻撃者が容易に知ることができる,等の欠点があり,これらを考慮 した対策が必要である. そこでパケットを大量に送信するサーバーの近くのノードに囮となるサーバー を配置し,そこで攻撃を受けさせる.これにより正常なトラフィックには影響を 与えずに,標的サーバーおよび,その経路に対する DDoS 負荷を低減させること, またその際,Locator/ID Separation Protocol (LISP) を用いることで対処後のシ ステム構成について秘匿することを提案する. これに基づき,本提案を実現するためのマップテーブルを LISP のマップテー ブルとは別にマップサーバーに組み込み,この 2 つのマップテーブルを利用する ことで本来の LISP の動作をさせつつ,DDoS 攻撃対処も実施できるシステムの プロトタイプを開発した.このシステムについて高負荷環境で実験し,提案が実 現可能であることを確認した.またこの結果について考察し,解決すべき今後の 課題とその解決方針を提案する. キーワード DDoS mitigation,LISP,囮サーバー ∗ 奈良先端科学技術大学院大学 情報科学研究科 情報処理学専攻 修士論文, NAIST-ISMT1151050, 2013 年 2 月 7 日. i Proposal of DDoS attack mitigation using two-step map table lookup on LISP∗ Toshifumi Saito Abstract DDoS attacks are serious threats. Although many countermeasures to DDoS attacks have been developed and practiced, most of them drop both attack traffic and legitimate communications. Furthermore, current countermeasures are easily recognized or evaded by attackers. In this paper, I propose a DDoS countermeasure that has the potential to decrease legitimate communications while mitigating DDoS attacks and hiding itself from attackers. The key idea of my proposal is creating decoy servers and decoy routers on ingress points of a DDoS attack by an extended LISP. The neighborhood of the machine which transmits large quantities of packets is set up as a decoy where the attack occurs. The effect on normal traffic is reduced, and the targeted machine and the route’s DDoS load are reduced. To address this problem, I propose Locator/ID Separation Protocol (LISP) to conceal the post mitigation effect from the attacker. Based on this, in order to realize my proposal, I developed a prototype system which can enforce DDoS mitigation. This prototype utilizes the combination of both the LISP Map Table and another Map Table to execute the original LISP. Keywords: DDoS mitigation,LISP,Decoy servers ∗ Master’s Thesis, Department of Information Processing, Graduate School of Information Science, Nara Institute of Science and Technology, NAIST-IS-MT1151050, February 7, 2013. ii 目次 1. はじめに 1 2. 関連研究 3 3. 提案 7 3.1 LISP を使用する意義について . . . . . . . . . . . . . . . . . . . . 7 3.1.1 LISP とは . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 3.1.2 本提案における LISP の役割 . . . . . . . . . . . . . . . . . 9 3.2 提案の内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 3.3 二段階マップテーブル . . . . . . . . . . . . . . . . . . . . . . . . 11 3.4 2-MapLISP の設計 . . . . . . . . . . . . . . . . . . . . . . . . . . 11 3.4.1 オペレーター . . . . . . . . . . . . . . . . . . . . . . . . . 13 3.4.2 マップサーバー . . . . . . . . . . . . . . . . . . . . . . . . 13 3.4.3 流入口 LISP ルーター . . . . . . . . . . . . . . . . . . . . . 15 3.4.4 囮 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 3.4.5 要求事項との対応 . . . . . . . . . . . . . . . . . . . . . . . 15 3.4.6 使用した LISP の実装 . . . . . . . . . . . . . . . . . . . . . 16 4. 評価 4.1 4.2 18 実験 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 4.1.1 仮想サーバーを用いた動作確認 . . . . . . . . . . . . . . . 18 4.1.2 物理環境における負荷試験 . . . . . . . . . . . . . . . . . . 21 2-MapLISP の効果 . . . . . . . . . . . . . . . . . . . . . . . . . . 38 4.2.1 局所化の効果 . . . . . . . . . . . . . . . . . . . . . . . . . 38 4.2.2 秘匿化の効果 . . . . . . . . . . . . . . . . . . . . . . . . . 38 4.2.3 継続性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 5. 課題と考察 5.1 40 囮の設置について . . . . . . . . . . . . . . . . . . . . . . . . . . . iii 40 5.2 対処の秘匿について . . . . . . . . . . . . . . . . . . . . . . . . . 40 5.3 継続性の向上 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 5.4 対処完了時間について . . . . . . . . . . . . . . . . . . . . . . . . 44 5.5 規模を拡大した際の適用について . . . . . . . . . . . . . . . . . . 45 5.6 再帰的問い合わせ DDoS 攻撃と反射型 DDoS 攻撃について . . . . 46 6. おわりに 48 謝辞 49 参考文献 50 付録 54 A. 拡張マップサーバーのソースコード 54 A.1 main.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 A.2 main.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 A.3 reply.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 iv 図目次 1 LISP の通信の流れ . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2 2-MapLISP の流れ . . . . . . . . . . . . . . . . . . . . . . . . . . 12 3 オペレーターが行う処理 . . . . . . . . . . . . . . . . . . . . . . . 13 4 マップサーバーの処理の流れ . . . . . . . . . . . . . . . . . . . . 14 5 流入口 LISP ルーターの処理の流れ . . . . . . . . . . . . . . . . . 16 6 仮想サーバーによる実験 . . . . . . . . . . . . . . . . . . . . . . . 19 7 仮想サーバーによる実験 2 . . . . . . . . . . . . . . . . . . . . . . 20 8 iperf を使用した実験 . . . . . . . . . . . . . . . . . . . . . . . . . 22 9 流入口ルーター (iperf) 24 10 被害側,囮側 LISP ルーター (iperf) . . . . . . . . . . . . . . . . 24 11 被害側,囮側サーバー (iperf) . . . . . . . . . . . . . . . . . . . . 24 12 Avalanche290 を使用した実験 . . . . . . . . . . . . . . . . . . . . 25 13 流入口ルーター (Avalanche) 27 14 被害側,囮側 LISP ルーター (Avalanche) 15 被害,囮サーバー (Avalanche) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 . . . . . . . . . . . . . . . . . . . 27 16 流入口ルーター (http GET) . . . . . . . . . . . . . . . . . . . . . 28 17 被害側,囮側 LISP ルーター (http GET) . . . . . . . . . . . . . 29 18 被害,囮サーバー (http GET) . . . . . . . . . . . . . . . . . . . 29 19 流入口ルーター (失敗例 1) . . . . . . . . . . . . . . . . . . . . . 31 20 被害側,囮側 LISP ルーター (失敗例 1) 21 被害,囮サーバー (失敗例 1) 22 流入口ルーター (失敗例 2) 23 被害側,囮側 LISP ルーター (失敗例 2) 24 被害,囮サーバー (失敗例 2) . . . . . . . . . . . . . . 31 . . . . . . . . . . . . . . . . . . . . 32 . . . . . . . . . . . . . . . . . . . . . 32 . . . . . . . . . . . . . . 32 . . . . . . . . . . . . . . . . . . . . 33 25 流入口ルーター (LISP で扱えるサイズを超えた場合) . . . . . . . 34 26 流入口ルーター OutOctets (LISP で扱えるサイズを超えた場合) . 34 27 被害側,囮側 LISP ルーター (LISP で扱えるサイズを超えた場合) 35 28 被害,囮サーバー (LISP で扱えるサイズを超えた場合) . . . . . . 35 v 29 流入口ルーター (フラグメンテーションした場合) . . . . . . . . . 36 30 流入口ルーター OutOctets (フラグメンテーションした場合) . . 36 31 被害側,囮側 LISP ルーター (フラグメンテーションした場合) . . 36 32 被害,囮サーバー (フラグメンテーションした場合) 37 表目次 vi . . . . . . . 1. はじめに 今日ではインターネットは社会に浸透し,多くの企業や組織,団体等がこれを 使用して情報の公開,配信や商取引等,多種多様なサービスの提供を行っている. そうした中で,以前から DDoS (Distributed Denial of Service) 攻撃などのイン ターネット上のサービスの妨害を目的とした攻撃の存在が知られている. DDoS 攻撃は標的サーバーに対して処理能力を上回る量のパケットを送出する 攻撃である [6].最近の傾向では,Header と呼ばれる攻撃者が Commnad&Control と呼ばれる制御用サーバーから攻撃の実行プログラムが仕掛けられた Bot と呼 ばれるサーバーに命令をだす,ボットネットによって DDoS 攻撃を発生させるこ とが多い [3].DDoS 攻撃は正規の通信を装っていることが多く,加えて送信元を 偽装していることもあり,防御が困難である.企業アンケートの分析 [1] によれ ば,DDoS 攻撃が行われる動機としては,政治的や社会的な意図を持つハクティ ビズムと公共物の破壊を意図するバンダリズムが大半を占め,政府や企業,社会 インフラといったものが直接の標的になりやすく,さらにそれらを利用する個人 も影響を受けると言える.加えて攻撃は大規模化する傾向にあり,10 Gbps 程度 のフラッドベースの DDoS 攻撃が常態化しており,また最大規模の攻撃となると 60 Gbps や 100 Gbps 超の攻撃も確認されている.大規模化の背景には例えば 3G, 4G に対応したスマートフォンや PC の低価格化により個人での所有が常態化した ことにより,ボットネットが利用できる機器が増加したこと等,技術の進歩や普 及に伴い大量のトラフィックを生成できるようになっていったことが考えられる. またフラッドベースとアプリケーション層の両方の攻撃コンポーネントを持つ複 雑なマルチベクトルの DDoS 攻撃が急速に普及しているという指摘や,IPv6 の DDoS 攻撃の報告もあり,攻撃の手法や対象は変化や拡大を続けていると言える. DDoS 攻撃に対する防御としては,サーバーやネットワーク機器の性能を強化す ることや,ブラックホールルーティング [25,26],IDS (Intrusion Detection System) や IPS (Intrusion Prevention System) [10] の設置等,様々な方法がある.しかし, これらの対策では標的となったサーバーやネットワークに対するトラフィック量 を減少することは可能だが,インターネット上に流れる不正なトラフィックを減 少させることはできず,インターネットへの影響は考慮されていないといえる. 1 さらに,対処の方法によっては正常なパケットと攻撃パケットを区別することな く破棄してしまうものもある.これは即ち,対処することによって通信を妨げ, 攻撃者の目的を達成,もしくは目的達成の一助となってしまうということである. こうした状況を解決するためには,正常な通信には影響を与えずに,ネットワー ク的に攻撃サーバーに近い位置で攻撃を抑制し,インターネット上を不正なトラ フィックが流れることを極力防ぐような対処法が必要である. そこで,本提案では標的サーバーおよび経路上の DDoS 負荷を減らすこと,正 常なパケットを破棄等することなく対処すること,対処の詳細を攻撃者から隠す ことの 3 点の達成を目指す.この達成のため,被害サーバーと同様の動作をする 囮のサーバーと,Locator/ID Separation Protocol (LISP) [27] のルーティングの 仕組みを改良して使用する.LISP は IP アドレスの ID の機能と Locator の機能を 分けて運用することができるが,この際,1 つの ID に対して複数の Locator を登 録できる特性を持つ.この特性を利用し,囮と被害サーバーの ID を同じにし,ど ちらと通信しているか認識が困難な状況を作り出すことが LISP の主な役割であ る.この 2 つを用いてネットワーク的に攻撃サーバーに近い位置に囮のサーバーを 設置して攻撃を受けることで,標的サーバーおよび,攻撃サーバーから標的サー バーまでの経路に対する DDoS 負荷を低減させ,正常に通信し続けると同時に, 対処後のシステム構成について秘匿し,更なる攻撃の抑制につながるシステムの 提案を行う. 以下,第 2 章では関連研究について述べる.第 3 章では提案手法について述べ る.第 4 章で評価,第 5 章で課題と考察について述べ,最後に本提案のまとめを 述べる. 2 2. 関連研究 DDoS 攻撃対策は,大きく分けて 4 つの種類に分類できる [6].DDoS 攻撃を起 こしにくくする「予防」,DDoS 攻撃の発生をすぐに発見する「検知」,DDoS 攻 撃の発生源を特定する「発生源特定」,特定した攻撃発生源に対して何かしらの 対抗策を行う「事後対応」である. 「予防」 は DDoS 攻撃を発生させにくくする予防技術の事である.DDoS 攻撃 を行う攻撃者は,Spoofing されたパケットを攻撃に用いることが多い.Spoofing とはパケットの発信元を偽装することで,パケット発信源を隠す技術のことであ る.この Spoofing されたパケットを,送信できないようにしたり,送信できたと しても中継ルータなどでフィルタリングする技術が「予防」 である.この代表 的な例に,Ingress/Egress Filtering [21, 24] がある.Ingress Filtering は,外部の ネットワーク(WAN)から自身の管理するネットワーク(LAN)にパケットが 入る際に,そのパケットが Spoofing されていないか確認するフィルタリング技 術である.Egress Filtering は,自身の管理するネットワークから外部のネット ワークにパケットが出る際に,そのパケットが Spoofing されていないか確認する フィルタリング技術である.Ingress / Egress Filtering による予防は BCP (Best Current Practice) [22] として,インターネットサービスプロバイダ(ISP)事業 者で広く実践されている. 「検知」 はサーバで DDoS 攻撃が発生した際に,その事をいちはやく発見し, サーバ管理者に伝える検知技術の事である.DDoS 攻撃をすばやく発見すること で,対策が容易になり被害も最小限に食い止める事が可能となる.例としては IDS や IPS [10] が挙げられる.IDS は検知が主な役割となるが,IPS はパケットの破 棄も行う.しかし,IDS や IPS はシグネチャベースのアプリケーション層におけ る攻撃の検出に適するが,ステートテーブルの枯渇のため DDoS 攻撃に対処でき なかったという報告がある [1].もちろんシグネチャに登録されていない攻撃手 法が用いられた場合においても検出できない.一部の製品では有効なパケットを 使用する DDoS 攻撃の検出に必要なアノーマリベースの機能がいくつか用意され ているが,手動による設定の調整が必要であり,また攻撃によっては識別できな いものもあり,完全ではない.加えて IPS で偽陽性の誤検知をした場合,正常な 3 パケットを破棄してしまい,通信を妨げることとなってしまう. 「発生源特定」 は,DDoS 攻撃が発生した際に,攻撃源をすばやく特定する ことで,その攻撃源からのパケットを遮断ことや,攻撃源をインターネットから 取り除くことで,攻撃を抑える技術である.これにより Spoofing に対抗するこ とも可能となる.また,攻撃者を特定することで法的な責任を問うことも可能と なり,DDoS 攻撃の抑制にも繋がる.発生源特定の代表的な手法としては,IP- TraceBack [9] と Packet-Marking [28] が挙げられる.IP-TraceBack は,パケット がルータを通過する際に,パケットの情報を一定確率でルータに記録しておく方 式であり,Packet-Marking は,パケットがルータを通過する際に,パケット自身 に通過したルータの情報を追記していく方式である. 「事後対応」は DDoS 攻撃が発生した際に,何かしらの防御活動を行いサーバ を守る技術であり,前述の「発生源特定」による情報も用いられ,被害を最小限 にするためにすばやく的確に対処することが求められる.本研究はこの「事後対 応」に分類される研究であるため,これらのうち,ここでは「事後対応」の現状 について考察する. 「事後対応」に分類される技術としては,ルーティングによるもの,ファイア ウォールによる対処,ロードバランサーの使用や,その他にも様々なものがある. しかし,これらの対策手法はそれぞれ欠点を持っている. ルーティングによる対策は,ブラックホールルーティング [25, 26] が挙げられ る.ブラックホールルーティングではパケット廃棄用のブラックホールルーター にパケットを送り対処するが,正常なパケットと攻撃パケットの区別を行うこと なく全て破棄してしまい,攻撃対処することで逆に通信の妨げとなるため,適切 な手法ではない. またファイアウォールで対処する場合を考えても,適正なトラフィックと不正 なトラフィックを分離することの困難さや,またファイアウォール自体がステー トテーブルの枯渇を狙った脅威に晒される等,IDS や IPS と同様の問題を抱えて いる [1]. ロードバランサーを利用して DDoS 負荷を分散させることを考えた場合,DDoS 攻撃のトラフィックの多さに圧倒されて処理能力を超えてしまい,対処できない 4 状況が考えられる.そのため別の手法と組み合わせ,ロードバランサー自体を保 護することを検討しなくてはならない [1]. その他,これらの対策手法以外にも様々な方法が考案されているが [6, 12],多 くの対策は防御するサーバーの直近で対処するため,被害サーバーの負荷を減少 できても経路上のトラフィック処理にかかる負荷を減少することはできない.さ らに,意図的もしくは誤って正常なパケットを破棄してしまうものもある.そし て,対策について攻撃者に知られずに実施する意図を持った手法については存在 していないと言え,これらに対応した手法が必要である. 経路上の DDoS 負荷に関しては,ファイアウォールを動的かつ広域に使用するこ とで対処するという研究 [15,32] も存在するが,これらはファイアウォールの欠点 を解消するものではない.既存の手法を利用する限りは同じ欠点を抱えることと なり,有効に対処力を向上させることはできない.また OpenFlow の利用 [16,17] によっても局所化やサービスの継続に関しては実施可能である.しかし OpenFlow を活用しようとするならば,参加する全てのノードが OpenFlow に対応している 必要がある.このことは OpenFlow のみに言える問題ではなく,ネットワーク全 体で防御を実施する手法の多くに言える問題である.これに対し,LISP は運用 者が必要と考える最小限のノードに LISP を適用するだけで現在のインターネッ トの仕組みの中に組み込んで使用することが出来る.そのため導入の難度を考え た場合,適用の規模が大きいほど本提案の方が有利であると言える.即ち,ホス トベースの DDoS 攻撃対処よりネットワークベースの DDoS 攻撃対処の方がより 有効に防御が可能であるものの,これを使用するには参加全ノードに当該方式を 適用する必要があり,コストをはじめ様々な問題があるため現実には適用は困難 であると言える.しかし LISP を利用した本提案ならば必要最小限の適用で実施 可能であるため,現実的に実施可能なネットワークベースの DDoS 攻撃対処とい う利点を持つと言える. 対処の秘匿に関しては,やはり意図した研究は存在しない.攻撃側が手法を巧 妙化させているのに対し,防御側は巧妙化という視点に欠け,後手に回る要因を 作り出していると言える.防御に関しても,単純に負荷を除去するだけではなく, 対処を認識させない方法を考える等,巧妙な対処という視点を持って臨むべきで 5 ある. 6 3. 提案 この章では提案について述べる.3.1 項では本提案で LISP を用いる理由につい て,3.2 項では本論文で提案する内容について,3.3,3.4 項では提案手法の一連の 流れやその方針について述べる. 3.1 LISP を使用する意義について 本提案においては,LISP の特性を利用することが重要な要素となっている.こ こでは,LISP の概要と LISP をどのように提案で用いるかを示す. 3.1.1 LISP とは 現在のインターネットでのルーティングおよび,アドレッシングアーキテクチャ では,IP アドレスという 1 つの番号空間によってデバイスの ID とネットワーク 接続方法の 2 つの機能を同時に表現している.しかし単一の番号空間で 2 つの機 能を同時に表現することによって,例えばマルチホーミングやトラフィックエン ジニアリングを行う際や,企業の合併等を背景としたデフォルトフリーゾーンの 急増等の場面において,IP アドレスの集約が困難になる等の弊害とも言える問 題が表面化してきている.これを解決するために考案されたものが LISP であり, これは Locator と Identifier を分けるプロトコルのことである.Locator とは IP ネットワーク上でノードが実際にどのルータに属しているかという情報であり, Identifier とは,ノードを一意に区別するという性質を指す. LISP はデバイスの Identifier を示す EID とその Locator を示す RLOC を 2 つの 異なる番号空間に分離することを可能にする.EID や RLOC は IPv4 や IPv6 の アドレスと同じ形式で表現される.IP アドレスから EID と RLOC の機能を分離 することで,RLOC の集約性が高まりルーティングシステムのスケーラビリティ が向上することや,マルチホーミングの効率と入力トラフィックエンジニアリン グ機能が改善される,といったメリットを得ることができる. 通常の LISP での通信の流れを図 1 に示す.あるクライアントが,ある EID を 持つノードに対して通信しようとしたとする.そのパケットは LISP での通信に用 7 いられるルーターに向かう.このルーターは xTR や PxTR と呼ばれる.xTR は Ingress/Egress Tunnel Router のことで,LISP サイトのノードのパケットの送受 信に使われるものである.具体的には,パケットは Ingress Tunnel Router (ITR) によってカプセル化され,その EID を配下に持つ Egress Tunnel Router (ETR) まで転送され,カプセルを解除して目的の EID を持つノードに運ばれる.PxTR は ProxyIngress/Egress Tunnel Router のことで,xTR と同様の働きをするが,こ れは非 LISP サイトにおいて LISP サイトとの通信に使われるものである.以下, これらのルーターを LISP ルーターと表現する.また,EID と RLOC の対応情報 はマップサーバーに蓄えられている.クライアントからのパケットが LISP ルー ターに到達すると,このマップサーバーに EID と RLOC の対応を問い合わせる. そしてマップサーバーから帰ってきた情報を使用して,パケットはクライアント 側の LISP ルーターから当該の RLOC を持つ LISP ルーターに送られる.送られ た先の LISP ルーターは目的の EID を持つノードにパケットを転送すると同時に, クライアント側の LISP ルーターに Map-Reply を返し,クライアント側の LISP ルーターで EID と RLOC の対応を記憶する.これにより,以降はマップサーバー に問い合わせずに通信できるようになる. クライアント クライアント側ルーター マップサーバー サーバー側ルーター サーバー パケット送信 マップリクエスト マップ情報を返す カプセル化・パケット送信 カプセル解除 パケット送信 Map-Reply パケット送信 カプセル化・パケット送信 Map-Reply 図 1 LISP の通信の流れ 8 カプセル解除 パケット送信 3.1.2 本提案における LISP の役割 本提案では LISP の以下の機能に着目している.まず第一に 1 つの EID に対し て複数の RLOC をマップサーバーに登録できるので,エンドユーザーが認識する アドレスを変更せずに複数の囮サーバーを作成できる.その際,囮サーバーを被 害サーバーと異なるネットワークに設置する場合であっても,EID は変化させる 必要はない.次に,EID の Locator を把握しているのは EID と RLOC の対応関 係を管理しているマップサーバーだけであり,攻撃者は誰に向けて通信している かは認識できるが,どこに向けて通信しているか,通信相手の場所については認 識できない.加えて LISP の通信はトンネルで接続された LISP ルーターを経由 するため,途中経路の情報の把握が困難である. これらの特性を利用すれば,攻撃者からは被害サーバーと通信しているのか, それとも囮のサーバーと通信しているのか,認識が困難な状況を作り出すことが 可能である.ただし提案を実現するためには,攻撃サーバーの送出する DDoS パ ケットが必ず囮サーバーに向かうようにルーティングする必要がある.しかし, 通常の LISP では RLOC に weight と priority を付与できるのみであり,意図した 通りにルーティングすることができない.そのため,xTR や PxTR 等の流入口 ルータ上で意図した通りにルーティングを行うための拡張が必要である. また,同様のことを実施するにはいくつか方法はあるが,LISP は商用のルータ に既に実装されており,実際のネットワークでの運用が可能である.これは LISP 以外の,実運用に至らない比較的新しいルーティングプロトコルに対する LISP の利点と言える.また,LISP では必要なノードに LISP を適用するだけで非 LISP ノードも含めて通信が実施できる.これは OpenFlow 等,参加する全ノードに適 用しなければならない手法に比して,金銭や手間といった視点から大きな利点が あると言える. 3.2 提案の内容 既にいくつか述べているが,既存の DDoS 攻撃対策手法の欠点をまとめると, 以下の 3 点が挙げられる. 9 (1) 防御するサーバーの直近で対処するため,被害サーバーの負荷は減少する が,被害サーバーに至る経路上のトラフィック処理にかかる負荷を減少する ことはできない. (2) 正常なパケットと攻撃パケットを区別することなく破棄,もしくは区別に 失敗して誤破棄し,通信の妨げとなる. (3) 対処の方法や構成等,その詳細を隠す意図がないので,対策手法によって は攻撃者に容易に対応されてしまう. 本提案においてはこれらの問題に対し,以下の方針で対応する. (1) ネットワーク的になるべく攻撃サーバーに近い位置で対処することで被害 サーバーに至る経路上の負荷も軽減する. (2) パケットを破棄せず,正常なパケットには囮サーバーに通常と同様の応答 をさせる. (3) LISP を使い,被害サーバーと囮サーバー間で同じ Endpoint Identifier (EID) を付与する. 具体的には次の通りである.想定として,トレースバック [31] 等の既存の技 術で攻撃パケットの発信元が判明しているものとする.この状態においてパケッ トを大量に送信するサーバーに対し,ネットワーク的になるべく近い位置に被害 サーバーと同様の動作をする囮のサーバーを配置して攻撃を受けさせる.これに より,正常なパケットには通常と同様の応答をさせ,攻撃と関係のないトラフィッ クには影響させずに対処を行うと同時に,DDoS 攻撃を局所で処理し,標的サー バーと標的サーバーに至る経路上の DDoS 負荷を軽減させる.加えて LISP を使 用して被害サーバーと囮となるサーバー間で同じ EID を付与することで,通信先 が被害サーバーから囮サーバーに変化したことを攻撃者が把握するのを防ぐ. 10 3.3 二段階マップテーブル LISP では RLOC を複数設定した場合,ルーターに weight や priority を付与し て各ルーターの通過の頻度や優先順位を操作することは出来るが,意図した通り に自在にルーティングすることのできる機能はない.そこで,本提案ではマップ サーバーが本来持つ,各 LISP ルーターからの map-regist パケット受信によって 作成したルーティングテーブルとは別に,トラフィック局所化用のテーブルを持た せた.これはオペレーターが手動でアドレスを入力することで作成することが出 来る.攻撃を検知したなら流入口と宛先,そして囮のサーバーと結ぶためのルー ターのアドレスを入力し,トラフィック局所化用のテーブルを作成する.その状 態で流入口の LISP ルーターのプログラムを再起動させると,それまでに学習し たマップキャッシュがクリアされてマップサーバーに再度の問い合わせを行う. マップサーバーが受信する主なパケットとしては,RLOC と EID の関連を記憶 するための map-regist パケットと,マップサーバーが記憶した経路をルーターが 問い合わせるために用いる map-request パケットがあり,またその他 LISP に関係 ないパケットを受ける事もあるが,このうち LISP ルーターから map-request を 受信したときのみ,map-regist パケットから作成したテーブルの検査の前にトラ フィック局所化用のテーブルを検査する.検査した結果,map-request が攻撃の流 入口から送られたものであり,かつ問い合わせ内容が被害 EID であった場合,こ れらと組で登録されている,提案手法で作成したトラフィック局所化用のテーブ ルにある RLOC を返す.このとき,map-regist パケット受信によって作成した本 来のルーティングテーブルの検査には移行せずに手順を終える.リクエストの送 り主が流入口のルーターでなかったり,宛先が被害 EID でない場合は,本来の手 順に戻り,マップサーバーの本来持つテーブルを使用して経路を返す.以降,提 案手法を 2-MapLISP と呼ぶ. 3.4 2-MapLISP の設計 図 2 に 2-MapLISP における処理の流れを示す.まず想定として,ある時点に おいて被害サーバーに対する DDoS 攻撃が発生し,既存の方法で検知やトレース 11 オペレーター マップサーバー 流入口ルーター DDoS攻撃検知 トレース Decoy設置 囮 囮のEID、RLOC 流入口のRLOC 登録 マップキャッシュクリア マップリクエスト Decoyとマッチ 通信 Decoy削除 図 2 2-MapLISP の流れ バック等を行い,攻撃がどこから来ているか判明しているものとする.この状態 で,攻撃パケットの流入口となっている LISP ルーターに対してネットワーク的に なるべく近い位置に,囮サーバーおよび,その通信に使う LISP ルーターを設置 する.囮サーバーは被害サーバーと同じ EID を持ち,同じ動作をする.囮を設置 したならば,オペレーターは手動で囮への経路情報をマップサーバーに登録する. 次に,攻撃パケットの流入口となっている LISP ルーターのマップキャッシュを 削除する.これは,マップサーバーに囮サーバーへの経路情報を設定しても,流 入口の LISP ルーターに被害サーバーへのマップキャッシュが残っていると,マッ プサーバーへの問い合わせをすることなく被害サーバーへパケットが流れ続けて しまい,囮サーバーへの経路を学習できないためである.上記の状態において流 入口の LISP ルーターにパケットが届くと,キャッシュがクリアされているため 目的のサーバーに向けてパケットを転送できないので,流入口の LISP ルーター はマップサーバーへ問い合わせを行う.するとマップサーバーは囮サーバーに向 かうための RLOC を返すので,流入口の LISP ルーターはこれを記憶し,以降の 通信については問い合わせなしに囮サーバーへ向かうことになり,攻撃を局所化 することができる. 12 3.4.1 オペレーター 図 3 にオペレーターが行う処理について示す.マップサーバーへの囮の経路情 報の登録および,流入口 LISP ルーターのマップキャッシュクリアについては手 動で行う.これらの操作については自動的に実施する方が利便性は高いが,その ためにはマップサーバーや囮の LISP ルーターから準備ができたことを伝えるパ ケットを送信してトリガーとする必要がある.しかしこれは外部からの操作を可 能にするということであり,セキュリティ上考慮しなければいけない課題が多い. そのためここでは各種操作について手動で実施することを前提としている. IF DDoS 攻撃検知 THEN 攻撃源のトレース THEN 流入口 LISP ルーター近くに囮サーバー設置 THEN リストに被害 EID,囮と流入口の RLOC を入力 THEN 流入口 LISP ルーターのマップキャッシュクリア END IF IF DDoS 攻撃終了 THEN 囮サーバー削除 END IF 図 3 オペレーターが行う処理 3.4.2 マップサーバー 図 4 にマップサーバーの処理の流れについて示す.通常の LISP のマップサー バーは,1 つの EID に対して weight と priority を付与して複数の RLOC を設定 できる.しかし,2-MapLISP は流入口の LISP ルーターと囮の LISP ルーターを 確実に結びつけることを意図し,これは weight と priority の設定のみでは実現 できないため,そのための仕組みを組み込む必要がある.本研究では,通常の手 順で用いられる EID,RLOC と weight や priority の情報とは別に,被害 EID お よび流入口と囮の RLOC の,3 つの情報からなるリストをマップサーバーに作成 13 させることで,流入口の LISP ルーターと囮の LISP ルーターを確実に結びつけ, 解決した.このトラフィック局所化のためのリストについては前述の通り,オペ レーターが流入口ルーターの RLOC,被害サーバーの EID,そして囮と通信させ るためのルーターの RLOC を手動で入力することで作成する.マップサーバー が map-request を受信したなら,まずはこの局所化のためのリストの検査を行う. 流入口の LISP ルーターからの map-request であるのか,宛先は被害 EID である のかを確認し,該当すれば囮の LISP ルーターの RLOC を返す.該当しなければ 通常の手順に移行させる. IF 被害 EID,囮と流入口の RLOC が入力された THEN 局所化リストの作成 END IF IF map-request 受信 THEN 局所化リストの参照 THEN IF リクエストが流入口 LISP ルーターから来た IF 被害 EID の RLOC を要求 THEN 囮の RLOC の TTL 検査 IF 囮の LISP ルーターは存在する THEN 囮の RLOC を返す BREAK ELSE 通常の手順に戻る END IF ELSE 通常の手順に戻る ENDIF ELSE 通常の手順に戻る END IF END IF 図 4 マップサーバーの処理の流れ 14 3.4.3 流入口 LISP ルーター 図 5 に流入口 LISP ルーターの処理の流れを示す.流入口の LISP ルーターにお いて DoS パケットの通過を既存の方法によって検知したなら,前述のようにオペ レーターは得られた情報をマップサーバーに入力し,局所化のリストを作成する ための手順を進めていく.マップサーバーにおいて局所化リストの作成が完了し, 局所化するための準備が完了したならば,オペレーターが手動で流入口の LISP ルーターのマップキャッシュを削除する.これによって流入口の LISP ルーターは 宛先情報を再度取得しなければならなくなり,map-request を送信する.マップ サーバーではこれに対して囮の LISP ルーターの RLOC を返し,流入口の LISP ルーターはその情報を記憶するので,以降に流入口の LISP ルーターが被害 EID 宛のパケットを受け取った際には,全て囮の LISP ルーターへと送るようになる. 3.4.4 囮 囮の LISP ルーターにおいては,設置して LISP ルーターの処理を開始するの みであり,特別の手順は必要としない.このルーターは設置の手間を省くため既 存の物理サーバー等としても構わないが,仮想サーバーを新たに設置する方が自 由度が高く,より効率的に局所化が図れる.同様に囮のサーバーも被害サーバー の完全なコピーを設置するのみである.これに関しては仮想サーバーでの設置が 基本となる. 3.4.5 要求事項との対応 本提案が要求事項を満たしているか確認する.まず,被害サーバーだけでなく 経路上の負荷も除去するということについては,攻撃パケットの流入口となってい る LISP ルーターの近くに設置した囮のサーバーで対処することによって,DDoS 負荷を局所化して対処することができる. また,攻撃と関係のないトラフィックに影響せずに対処を行うことについては, 被害サーバーと同様の動作をする囮のサーバーで対処することで,正常なパケッ トには通常と同様の応答をさせるので,影響せずに対処することができる. 15 パケットを宛先に送る DoS パケットを検知 IF マップキャッシュがクリアされた IF パケット受信 THEN map-request THEN 返ってきた RLOC にパケットを送る THEN マップキャッシュに記憶 IF パケット受信 IF 宛先がキャッシュされている THEN キャッシュに従ってパケットを送る THEN IF TTL 切れ THEN 当該キャッシュの削除 THEN map-request END IF ELSE map-request END IF ENDIF END IF END IF 図 5 流入口 LISP ルーターの処理の流れ 最後に,攻撃者に認識させずに対処を行うことについては,クライアントから 見ると通信相手の IP アドレス (EID) に変化がなく,また RLOC を把握している のはマップサーバーだけであるので,クライアントからは ID や Locator の変化 を認識することができない.これにより,アドレスから通信相手が囮サーバーに 変化したことを認識させない.これらから,本提案は要求事項を満たす. 3.4.6 使用した LISP の実装 元のプログラムは上野らの作成した LISP のプログラム [7] であり,これを改変 して 2-MapLISP を作成している.このプログラムの特徴はいくつかあるが,最 大の特徴は 16 • オープンソース • control-plane 機能 • 汎用 OS (Linux) 上で動作 ということである. RLOC と EID のマッピングを解決する機能を control-plane と呼ぶが,具体的 には control-plane は map-request/ reply や map-regist など,LISP の運用を自 動化するための種々の機能を含むものであり,必須の機能である.オープンソー スでこの機能を有するのは,現時点では同プログラムのみである.2-MapLISP は マップサーバーに新たに機能を組み込むことで実現するため,完全に独自でプロ グラムを作成するかオープンソースを改変して使用するか以外の選択肢はなく, 必須の機能といえる control-plane 機能を有するオープンソースの LISP プログラ ムが上野らのプログラム以外に存在しないことを考えれば,後者を選択する場合 は同プログラム以外の選択肢はないともいえる. また LISP はクラウド技術と相性が良く,特定のプレフィクスを第三者の運用す るクラウド内に配置するというユースケースが予想されるが,第三者の運用する クラウド内に物理的にルータを設置することは不可能であるため,仮想サーバー 上に LISP ルーターを構築することを想定し,同プログラムは汎用 OS 上で動作す るように作られている.本提案ではこれを利用して,必要な LISP ルーターを好 きなノード上で,2-MapLISP を実行するときのみ動作させることを前提としてい る.設置場所を選ばないということは局所化という本提案の目的を達成する上で 非常に有利である.局所化を図る上で最適な場所を選びやすく,また一ヶ所に局 所化させるだけでなく,設置個数を増やして負荷を分散させる等,状況に応じて 柔軟に対応することが出来る.また仮想サーバーを使用する場合,物理ルーター を常設する場合に比べてコスト面で優位であり,逆に設置の手間を省くために既 設のサーバーを利用する場合であっても,同プログラムはデーモンとしてバック グラウンドで動作させることが可能であるため,現在の処理を妨げずに利用可能 である. 17 4. 評価 この章では評価について述べる.4.1 項では実施した実験について,4.2 項では 本手法を適用できる規模および,解決を試みた 3 つの要件に対する評価について 述べる. 4.1 実験 4.1.1 仮想サーバーを用いた動作確認 まず,基礎検証として 1 台の物理サーバーの中に攻撃用の仮想サーバーと流入 口 LISP ルーターとして機能する仮想サーバーを 1 台ずつ用意し,提案通り経路 を曲げることが可能であるか確認した.なお実験の際の制約として,元となった 上野らのプログラムにおいて IPv4 の扱いに不具合があり,動作できないため,以 降の実験環境は全て IPv6 で用意した.この際の詳細な環境としては,以下の通 りである. • 物理サーバー(ホストサーバー) :CPU 4 コア,2.3 GHz メモリ 8 GB • 攻撃サーバー:1 台,CPU 1 コア,メモリ 512 MB • 流入口ルーター:1 台,CPU 4 コア,メモリ 4 GB • 被害,囮ルーター:各 1 台,CPU 1 コア,メモリ 768 MB • 被害,囮サーバー,マップサーバー,非 LISP ルーター:各 1 台,CPU 1 コ ア,メモリ 512 MB これを用意し,仮想ネットワークを構成した.トポロジを図 6 に示す.この状 態で攻撃サーバーにおいて,オプションを使用してデータ部サイズを最大にし, 送信間隔を最短に設定した ping6 のコマンドを実行させて負荷をかけ,その状況 下で経路が被害サーバーから囮サーバーへ変更することができるかを確認した. なおこの際,ルーターを一時的に停止させたりトラフィックを遮断したりするこ となく,負荷を受け続けたまま経路の変更を実施させる.この結果,意図した通 18 りに経路を変えることが出来た.このとき,オプションを使用して同環境におい て 1 秒間に何回パケットを送出しているか確認したところ約 120 回であったので, 計算すると 65535 × 8 × 120 bit で,約 63 Mbps に対応したことになる.確認し た範囲においては,1 台の仮想サーバーから ping6 でかけることのできる負荷は これが最大であった. 図 6 仮想サーバーによる実験 次に,負荷を増やすため同じ環境で攻撃サーバーを 10 台に増やして同様の実 験を行った.トポロジを図 7 に示す.この結果,経路の変更に関しては問題なく 実施できた.具体的には,攻撃サーバーが 1 台のときと同程度の時間で経路変更 を実施することができた. ただしこの際,各攻撃サーバーの ping6 の結果は以下のようになった. --- 2003::8801:203:278:156 ping statistics --63877 packets transmitted, 1083 received, +3 errors, 98% packet loss, time 833399ms rtt min/avg/max/mdev = 40.520/135.531/436.340/50.895 ms, pipe 26, ipg/ewma 13.047/212.541 ms これは 10 台の攻撃サーバーの中の 1 台の ping6 の結果であるが,他のサーバー も概ね同じような結果であった.これを見ると,大半のパケットがロスしてしまっ ていることがわかる.また実験の場において実際に ping6 の応答を監視していて も,完全に止まることは無いものの,1 台のときと比して明らかに応答が遅くなっ 19 図 7 仮想サーバーによる実験 2 ていることを確認した.このことから,攻撃サーバーから囮サーバーに至る経路 上は輻輳してしまっていたと言える. ただしこの最中に,図 7 中の PC router から Victim へ通常のの ping6 を実行し た結果は以下に示した通りである.これを見るとわかるように,大量のパケット ロスが発生するようなことはなかった.この結果から,意図した通りトラフィッ クは囮サーバーに向かっているため,その経路の外においては輻輳の影響を受け ずに通信を行うことが出来ると言える. --- 2003::8801:203:278:156 ping statistics --131 packets transmitted, 129 received, 1% packet loss, time 130091ms rtt min/avg/max/mdev = 0.395/0.961/3.390/0.506 ms またこの最中に,図 7 中の Bot を 1 台増やし,流入口ルーターを経由して PC router に対し通常の ping6 を実行した結果を以下に示す.この結果を見ると 36%の パケットロスが発生しており,攻撃サーバーと同じルーターを通じて通信するた めに輻輳の影響を受けてしまっているとわかる.ただし囮サーバーと通信を行う 場合のような大きな影響を受けることなく通信をすることが可能であると言える. 20 --- 2002::321:7654:ef98:edcb ping statistics --92 packets transmitted, 58 received, +6 errors, 36% packet loss, time 91384ms rtt min/avg/max/mdev = 18.456/63.799/187.048/37.391 ms 4.1.2 物理環境における負荷試験 次に,どの程度の負荷の中で使用できるか検証することを目的として,物理環 境での実験を行った.使用したサーバーは以下の通りである. 物理サーバー:SUN FIRE X2270 M2 SERVER CPU 2.40GHz 8 コア メモリ 12GB 10/100/1000Base-T イーサネット・ポート× 2 OS Debian6.0 4.1.2.1 iperf を用いた実験 まずはサーバーを 7 台用意して iperf を用い,実験環境における最大のネット ワークトラフィックが流れ続けている状況で 2-MapLISP の動作を確認した.実験 トポロジを図 8 に示す. iperf はネットワークのスループットを測定するためのフリーソフトウェアで あり,クライアントとサーバーを設定して実行することで両者の間を実際にトラ フィックを流してスループットを測定することが出来る.また本実験においては オプションを利用して実行時間,UDP の使用,帯域を指定して実施した.具体 的な実験の手順は次の通りである. • 予め iperf をサーバー設定で図 8 中の Victim と Decoy で起動しておく. • 実験時間を 150 秒間とし,15 秒経過の時点で Attacker で iperf をクライア ント設定で起動する. • この際オプションを使い,iperf の稼働時間を 120 秒間,UDP で帯域を 1Gbps に指定しておく. 21 図 8 iperf を使用した実験 • 60 秒稼働した時点で,2-MapLISP を使い Victim から Decoy へとトラフィッ クの宛先を変更する. • あらかじめ参加全ノードにおいて/proc/net/dev のデータをテキストに毎秒 書き出すシェルスクリプトを実行しておき,受信パケット数に係るデータ を収集する. この手順でトラフィックの変化をデータとして取得した.その結果を図 9∼図 11 に 示す.iperf を利用した実験は計 5 回試行しており,2-MapLISP による経路の切り 替えは 5 回とも成功している.ここで示すグラフはそのうちの 1 回の結果について 示したものである.横軸は経過時間を秒単位で表し,縦軸は前述の/proc/net/dev から得られた受信バイト数に係るカウンター値から計算した毎秒の平均データ転 送速度である.なお,実験時は Victim router と Decoy router で tcpdump を実行 しておき,2-MapLISP 実行時の状況の変化について目視によっても確認してい る.また,各サーバーが 10/100/1000Base イーサネット・ポートを使用している ため 1Gbps の帯域を指定しているが,これより大きい値を指定してもトラフィッ クの大きさに変化がないことを確認している.図 10 と図 11 から,トラフィック の宛先を変更し,また経路上のルーターからも負荷が除去できていることがわか 22 る.ただし,iperf 稼働 60 秒の時点で直ちに局所化できているわけではない.こ れは 2-MapLISP 実行時のタイムラグによるものである.すなわち,タイムラグ を考慮して開始 60 秒に手法の手順が完了できるように実施したのではなく,60 秒経過と同時に手法の実行に取り掛かった,ということである.この際の遅延に ついては,手動実行のため正確な時間ではないが,概ね 20 秒である.約 20 秒費 やして手順を完了させた後については,瞬時に経路の変更がなされるものであり, 2-MapLISP 実行後から実際に経路が切り替わるまでに一定の時間を要するとい うことではない.これについては受信バイト数のカウンター値による確認だけで なく,実験の場において tcpdump のモニターにより 2-MapLISP の実行と同時に 遅滞なく経路が切り替わっていることを確認している. この実験により,10/100/1000Base イーサネット・ポートで流れ得る最大帯域 幅のトラフィックを受けても,本実験環境程度の処理能力を持ったサーバーを用 いれば,各種リソースを消費しつくすことなく,意図した通りの送信先に経路を 変更することができるとわかった. なお,図 10 と図 11 を見ると被害側の LISP ルーターから被害サーバーにトラ フィックが流れる際に,わずかにドロップが発生していることが確認できるが, これについてはサーバーを入れ替える等して検証した結果,この実験で被害側の LISP ルーターとして使用したサーバーのみにおいて,大きなトラフィックを受け ても転送の際に約 908Mbps までしか転送せず,残りを破棄してしまう現象が発 生していることを確認した.他のサーバーでは同様の現象は発生しないため,プ ログラムの不具合ではなく何らかのハードウェア上の不具合であると考える. 4.1.2.2 Avalanche290 を用いた実験 次にサーバーを 6 台と Avalanche290 [2] を使用して実験を行った.Avalanche290 はネットワークの性能を試験するためのストレステストアプライアンス製品であ り,現実の状況に即した様々な設定で負荷をかけ,コンピューティングインフラ ストラクチャとネットワーク機器が過大なトラフィックに耐えられるかどうかを 試験するためのツールである.トポロジを図 12 に示す.iperf を利用した実験に おいて iperf クライアントであったサーバーを Avalanche290 に変更した点以外は 同じである.この状態で,Victim のサーバーに Avalanche290 からパケットを大 23 1000 Inlet LISProuter 900 800 700 Mbps 600 500 400 300 200 100 0 0 20 40 60 80 100 120 140 160 seconds 図 9 流入口ルーター (iperf) 1000 Victim LISProuter Decoy LISProuter 900 800 700 Mbps 600 500 400 300 200 100 0 0 20 40 60 80 100 120 140 160 seconds 図 10 被害側,囮側 LISP ルーター (iperf) 1000 Victim server Decoy server 900 800 700 Mbps 600 500 400 300 200 100 0 0 20 40 60 80 100 120 140 160 seconds 図 11 被害側,囮側サーバー (iperf) 24 量に送り,一定時間が経過したところで,2-MapLISP によりパケットの送信先を Decoy に変える.Avalanche290 を用いた実験により,帯域幅のみならず各種のリ ソースを消費させるような高負荷環境における 2-MapLISP の動作を確認するこ とが出来る. 図 12 Avalanche290 を使用した実験 Avalanche290 の設定できる項目は数多くあるが,ここでは DDoS 攻撃を模し た動作をさせるためのオプションを使用して,これに係る項目値を最大にし,そ の他は初期値のままとして実験を行った.具体的には次の通りである. • アクションの項目で「DNS A ⟨ 送信先アドレス ⟩ hoge.naist.jp」と入力し, DNS クエリによる UDP パケットを生成する. • Load の項目で,10,000,000SimUser/sec に設定する. • ホスト数の項目で,最大値である 1048576 を設定する. • 実際の DDoS 攻撃を模した動作をさせるためのオプションを選択して,UDP flood 攻撃を選択し,パケット生成レートを 1,000,000,000pps に設定する. Avalanche290 はトラフィックの作成の方法にも様々なやり方が用意されており, 中でも SimUser という概念が負荷に対する最も基本的な設定となっている.これ 25 は Avalanche290 が模す仮想ユーザーの人数を表す設定であり,この仮想ユーザー の各々がアクションの項目に記述した内容を実行するという想定で Avalanche290 は負荷を生成する. ここで示したものはあくまでも設定値であり,実際には環境に依存する部分があ るためここまでの性能を発揮できることは無いが,この設定によって Avalanche290 が生成できるネットワーク負荷を最大にして実験を行うことが出来る.実際には 700Mbps から 900Mbps 程度のトラフィック,約 18 万 pps のパケット生成能力を 確認している.偽装送信元アドレスの数については確認する手段はないが,これ についてはサーバーの能力等の制限を受ける事項ではないので,ホスト数に指定 した値がそのまま当てはまると考える.この状態で,以下の手順で実験を行った. iperf を用いた実験の場合と手順自体に大きな変更はない.この実験結果を図 13∼ 図 15 に示す.実験時は Victim と Decoy で tcpdump を実行しておき,2-MapLISP 実行時の状況の変化について目視によっても確認している. • Avalanche290 を 120 秒間稼働させる. • 60 秒稼働した時点で 2-MapLISP を実行し,図 12 中の Victim から Decoy へ とパケットの送信先を変更する. • あらかじめ参加全ノードにおいて/proc/net/dev のデータをテキストに毎秒 書き出すシェルスクリプトを実行しておき,受信パケット数に係るデータ を収集する. Avalanche290 が実際に稼働するのは 120 秒間であるが,グラフでは見やすさの ために Avalanche290 の稼働前後にトラフィックの流れていない状態を表示して いる.図 14 と図 15 を見てみると,やはり実行時のタイムラグが含まれた波形と なっているが,実際には手順を完了後直ちに経路が切り替わっている.これにつ いては iperf を用いた実験と同様,受信バイト数を後から確認するだけでなく,実 験の場において tcpdump のモニターにより 2-MapLISP の実行と同時に遅滞なく 経路が切り替わっていることを確認している.このことより,本実験環境程度の 性能のサーバーを用いれば,Avalanche290 が生成する程度の大きなトラフィック, 26 1000 Inlet LISProuter 900 800 700 Mbps 600 500 400 300 200 100 0 0 20 40 60 80 100 120 140 160 seconds 図 13 流入口ルーター (Avalanche) 1000 Victim LISProuter Decoy LISProuter 900 800 700 Mbps 600 500 400 300 200 100 0 0 20 40 60 80 100 120 140 160 seconds 図 14 被害側,囮側 LISP ルーター (Avalanche) 1000 Victim server Decoy server 900 800 700 Mbps 600 500 400 300 200 100 0 0 20 40 60 80 100 120 140 160 seconds 図 15 被害,囮サーバー (Avalanche) 27 高 pps,大量の偽装送信元アドレスを受けても各種リソースを消費しつくすこと なく,意図した通りの送信先に経路を変更することができることが証明できた. また,HTTP GET 実行中に 2-MapLISP で経路を曲げられるか実験を行った. これは被害,囮サーバーの両方に同じファイルを置いておき,Avalanche290 の仮 想ユーザーに GET コマンドを実行させることで行う.ファイルのサイズは 1GB とした.実験結果を図 16∼図 18 に示す.UDP での実験時に比べて帯域が著し く小さくなっているが,これは環境に依存しているものと考える.これ以外にも POST コマンド,GET コマンドを試し,転送するファイルも 1MB から 1GB まで 試し,また 2-MapLISP,元のプログラム,LISP 無しの状態で試したがどの場合 も同じ程度の帯域幅であったため,Avalanche290 の設定や 2-MapLISP における 不具合ではなく,実験環境によるものと考える.ただし pps 等については UDP による実験の際と変わらない値であった.この実験によって,コネクション通信 中であっても 2-MapLISP により経路を切り替え,囮サーバーと通信を再開する ことが可能であるとわかった. 100 Inlet LISProuter 80 Mbps 60 40 20 0 0 20 40 60 80 100 120 140 seconds 図 16 流入口ルーター (http GET) 28 160 100 Victim LISProuter Decoy LISProuter 80 Mbps 60 40 20 0 0 20 40 60 80 100 120 140 160 seconds 図 17 被害側,囮側 LISP ルーター (http GET) 100 Victim server Decoy server 80 Mbps 60 40 20 0 0 20 40 60 80 100 120 140 160 seconds 図 18 被害,囮サーバー (http GET) 29 4.1.2.3 失敗例について ただし,実験では図 19∼図 21 や図 22∼図 24 に示すような失敗例も確認され た.これらのグラフは cron [5] で snmpwalk [30] を 1 分毎に実行して総受信バイ ト数を取得し,作成している. cron はユーザの設定したスケジュールに基づいて指定したコマンドやシェルス クリプトなどを自動実行してくれるデーモンであり,ntp [20] 等を使用して各サー バーの内部時計を調整した環境においてこれを使用することで,同一のタイミン グでコマンドを実行させることが出来る. SNMP [23] はネットワーク監視およびネットワーク管理を行うためのプロト コルであり,管理される側である「SNMP エージェント」と,管理する側である 「SNMP マネージャ」の 2 つで構成される.本実験環境においてはエージェント, マネージャ共に各ノード自身とし,この状態で情報を取得するためのコマンドで ある snmpwalk を実行して自分の内部情報を取得し,テキストファイルに書き出 すことでデータの収集を行っている.取得するデータは ifHCInOctets というもの を主とし,これを取得することで総受信バイト数を知ることが出来る. 図 19∼図 21 では経路の変更を実施したところ,囮側にトラフィックが流れる ようになるが,被害側にも継続してトラフィックが流れ続けてしまっている.ま た流入口ルーターが Abalanche290 から受けたのと同程度のトラフィックが双方に 流れてしまっている.図 22∼図 24 では経路の変更を実施したところ,LISP ルー ターにおいては被害側から囮側へ経路が変更されたことが確認できるが,被害 サーバーを見てみると,経由するはずの LISP ルーターを介さずに直接被害サー バーにトラフィックが流入してしまっている. これらの現象はスイッチを介さずに直接サーバー同士を接続したら確認されな くなったことや,トラフィック総量の半分ずつを被害,囮サーバーで受信したり, 経路の変更を実施したにも関わらず被害サーバーのみにトラフィックが流れ続け る,というのではなく,流入口ルーターが Abalanche290 から受けたのと同量のパ ケットを全てのノードで受信している,といった状況から推測するに,2-MapLISP や LISP の不具合ではなく,スイッチが pps の大きさに耐えられなかったり,偽 装送信元アドレスの多さに Forwarding DataBase が溢れる等の不具合により,ブ 30 ロードキャストの状態に陥ってしまっていると考えられる.この際,iperf を用い た実験ではこの現象は観測されなかったことや,図 22∼図 24 のように bps を小 さくしても発生していることから考えて,bps には関係ない現象であると推測で きる.今回については,上述のようにスイッチを介さず直接サーバー同士を接続 することでこれを克服し,実験を実施している.4.1.2.2 項に示した実験について も,直接サーバー同士を接続した状態で実施している. 1000 Inlet LISProuter 900 800 700 Mbps 600 500 400 300 200 100 0 0 2 4 6 8 10 minutes 図 19 流入口ルーター (失敗例 1) 1000 Victim LISProuter Decoy LISProuter 900 800 700 Mbps 600 500 400 300 200 100 0 0 2 4 6 8 10 minutes 図 20 被害側,囮側 LISP ルーター (失敗例 1) 2-MapLISP は Linux 系の OS であればどれでも実行可能なプログラムであるの で,処理能力の高いサーバーで実行させることで簡単に性能を上げることが出来 る.しかし他の物理的なネットワーク機器はそのようなわけにはいかず,この失 31 1000 Victim server Decoy server 900 800 700 Mbps 600 500 400 300 200 100 0 0 2 4 6 8 10 minutes 図 21 被害,囮サーバー (失敗例 1) 100 Inlet LISProuter 80 Mbps 60 40 20 0 0 2 4 6 8 10 minutes 図 22 流入口ルーター (失敗例 2) 100 Victim LISProuter Decoy LISProuter 80 Mbps 60 40 20 0 0 2 4 6 8 10 minutes 図 23 被害側,囮側 LISP ルーター (失敗例 2) 32 100 Victim server Decoy server 80 Mbps 60 40 20 0 0 2 4 6 8 10 minutes 図 24 被害,囮サーバー (失敗例 2) 敗例のように,2-MapLISP を実行するサーバーが攻撃に対応する能力を持ってい たとしても,それより処理能力の低いネットワーク機器がボトルネックとなって 攻撃に対応できなくなることもある.従って,他の機器との連携を今後の課題と して考える必要がある. また,図 25∼図 28 に示すような不具合も確認された.これはカプセル化の際 にパケットが LISP で扱えるサイズを超えてしまったため,LISP ルーターがパ ケットを破棄してしまい,流入口ルーターにパケットが届いてもそこから先にパ ケットの転送を行えなくなってしまった状態である.図 25 から流入口ルーターは Avalanche からのトラフィックを受けていることがわかるが,送信バイト総数を 示す OutOctets をグラフ化した図 26 を見てみると,全くパケットが送信されて いない.またこのとき他のノードの受信バイト総数を確認してみても,図 27 や 図 28 に示すように,実際にパケットを受信していないとわかるし,tcpdump で も全くパケットを受信していないことを確認している. また,この状態からさらにパケットを大きくした場合の結果を図 29∼図 32 に 示す.図 29 で示す流入口ルーターの受信したトラフィックに比して,図 30 に示 す流入口ルーターから送信されるトラフィックや,図 31,図 32 に示す各経路の トラフィックが著しく小さくなってしまっている事がわかる. このとき Victim において tcpdump でパケットをキャプチャしたところ,次の ようなパケットを受信していた. 33 1000 Inlet LISProuter 900 800 700 Mbps 600 500 400 300 200 100 0 0 1 2 3 4 5 minutes 図 25 流入口ルーター (LISP で扱えるサイズを超えた場合) 1000 Inlet LISProuter 900 800 700 Mbps 600 500 400 300 200 100 0 0 1 2 3 4 5 minutes 図 26 流入口ルーター OutOctets (LISP で扱えるサイズを超えた場合) 08:51:10.967429 IP6 2001::200:ff:fe03:e664 > 2003::8801:203:278:156: frag (1448|65) — これはパケットが分割されたが,大きい方のパケットがカプセル化の際に LISP で取り扱えるサイズを超えたため破棄されてしまい,小さい方のパケットのみが 転送された結果である.同じ状態で LISP の使用をやめた場合,次のようなパケッ トを受信する. 34 1000 Victim LISProuter Decoy LISProuter 900 800 700 Mbps 600 500 400 300 200 100 0 0 1 2 3 4 5 minutes 図 27 被害側,囮側 LISP ルーター (LISP で扱えるサイズを超えた場合) 1000 Victim server Decoy server 900 800 700 Mbps 600 500 400 300 200 100 0 0 1 2 3 4 5 minutes 図 28 被害,囮サーバー (LISP で扱えるサイズを超えた場合) 08:55:23.106325 IP6 2001::200:ff:fe03:a71a > 2003::8801:203:278:156: frag domain: 44[—|domain] 08:55:23.106329 IP6 2001::200:ff:fe03:a71a > 2003::8801:203:278:156: frag (0|1448) 46082 > (1448|65) — これらは LISP ルーターのプログラム中に定義されている MTU 値を上げること で対応可能であるが,他のノードとの矛盾が生じないように注意する必要がある. 35 1000 Inlet LISProuter 900 800 700 Mbps 600 500 400 300 200 100 0 0 2 4 6 8 10 minutes 図 29 流入口ルーター (フラグメンテーションした場合) 1000 Inlet LISProuter 900 800 700 Mbps 600 500 400 300 200 100 0 0 2 4 6 8 10 minutes 図 30 流入口ルーター OutOctets (フラグメンテーションした場合) 1000 Victim LISProuter Decoy LISProuter 900 800 700 Mbps 600 500 400 300 200 100 0 0 2 4 6 8 10 minutes 図 31 被害側,囮側 LISP ルーター (フラグメンテーションした場合) 36 1000 Victim server Decoy server 900 800 700 Mbps 600 500 400 300 200 100 0 0 2 4 6 8 10 minutes 図 32 被害,囮サーバー (フラグメンテーションした場合) 37 4.2 2-MapLISP の効果 この項では実験結果から得られた 2-MapLISP の効果について示す. 4.2.1 局所化の効果 4.1 項から流入口 LISP ルーターを経由して被害サーバーへ至るトラフィックに ついて,高負荷環境においてもマップサーバーに用意した局所化リストを利用し て宛先を囮サーバーに変更することができるとわかった.これを使い,通信経路 上の適宜の位置に囮サーバーを設置して経路変更することでトラフィックの局所 化が可能である. 4.2.2 秘匿化の効果 対処の秘匿に関しては既述の通りである.即ち LISP の特性を利用すれば,エ ンドユーザーが認識するアドレスである EID を被害サーバーから変化させずに囮 サーバーを設置できる.またこの際,RLOC を把握しているのはマップサーバー だけであり,RLOC はマップサーバーと LISP ルーターのみが取り扱うものであ るため,エンドユーザーは通常は RLOC を認識することはない.これらのことか ら,通信相手が被害サーバーから囮サーバーに変化しても,アドレスの変化から これを判断することはできず,経路変更による対処について攻撃者が把握するの は困難である. 4.2.3 継続性 サービスの継続性に関しては,経路を変更した先にある囮サーバーが被害サー バーを完全にコピーしたものであれば,被害サーバーが提供する何らかのサービ スを同じように囮サーバーも提供することが出来る.4.1.2.2 項ではファイルのダ ウンロードを例にとって実験を実施した.ただし,これが可能であったことが経 路変更後に対するあらゆるサービスの継続を可能と判断する根拠となるわけでは ないので,更なる検証が必要である.また 4.1 項で示したように,経路変更したト 38 ラフィックの規模によっては輻輳して応答の悪い状態となり,サービスの提供が 困難となる場合もあるので,状況に応じて囮の数を増やす等の措置が必要である. 39 5. 課題と考察 この章では今後の課題と考察について述べる. 5.1 囮の設置について 流入口ルーターに対して適宜の位置に囮サーバーと LISP ルーターを設置する ことでトラフィックの局所化が図れる.本提案における LISP ルーターは Linux 系の OS 上で動作するプログラムとして提供されるので,その設置位置や方針に 関しては一定の柔軟性を有すると言える.固定された物理ネットワーク機器では ないので最も有利になる場所を選んで設置可能であるし,また常時設置する必要 がないのでコスト面の有利さも挙げられる.また動作させるのは物理サーバー上 でも仮想サーバー上でもどちらでも良い.既存の物理サーバーを利用すれば設置 の手間を省くことが出来るし,仮想サーバーを利用すればより柔軟な設置が可能 となる.ただし囮サーバーに関しては被害サーバーのコピーという性質上,仮想 サーバーでの設置が基本となるので,ルーターとサーバーの両者を仮想サーバー で設置する場合の手間については留意しておかねばならない. 5.2 対処の秘匿について 本提案においては LISP の特性を利用し,囮サーバーを利用した対処について 攻撃者に認識させない狙いがある.ただし経路が被害サーバーから囮サーバーに 変化したことを攻撃者が確認するための手段として,traceroute の利用が挙げら れる.LISP は traceroute に対応しているので,LISP 使用中であっても traceroute で経路の変化を把握することは可能である. 具体例を挙げると,実験環境において LISP 未使用で traceroute6 を実行した際 の結果は以下のようになる. 40 traceroute to 2003::8801:203:278:156 (2003::8801:203:278:156) 1 2001::a00:27ff:fe63:6da1 (2001::a00:27ff:fe63:6da1) 3.259 2 2002::321:7654:ef98:edcb (2002::321:7654:ef98:edcb) 5.488 3 2012::a00:27ff:fe63:1234 (2012::a00:27ff:fe63:1234) 5.178 4 2003::8801:203:278:156 (2003::8801:203:278:156) 7.807 ms , 30 hops ms 2.982 ms 5.394 ms 9.329 7.568 ms max, 80 byte packets ms 2.827 ms ms 5.288 ms ms 8.099 ms 7.413 ms 次に,同環境で LISP 使用中に traceroute6 を実行した際の結果は次の通りである. traceroute to 2003::8801:203:278:156 (2003::8801:203:278:156) 1 2001::a00:27ff:fe63:6da1 (2001::a00:27ff:fe63:6da1) 0.775 2 2012::a00:27ff:fe63:1234 (2012::a00:27ff:fe63:1234) 7.299 3 2003::8801:203:278:156 (2003::8801:203:278:156) 7.824 ms , 30 hops ms 0.617 ms 7.167 7.984 ms max, 80 byte packets ms 1.078 ms ms 6.538 ms 8.104 ms LISP では LISP ルーター間の通信にはトンネルが使用されるが,上段の LISP 使 用前の状態で 2002::321:7654:ef98:edcb のアドレスを持つルーターは LISP に対応 していないので,下段の LISP 使用後の状態では traceroute6 の結果に反映してい ない.しかし LISP に対応したルーターは LISP のカプセルを解除することがで きるので,通常通りカプセルを解除してマップサーバーに ICMP time-exceeded パケットの送り先を問い合わせることで,traceroute6 の結果に反映することが出 来る. しかし本提案においては経路の変更を攻撃者から秘匿することが目的の一つで あるため常に通常の結果が表示されるのは望ましくない.従って traceroute に対 する対策が必要である.最も簡単に実行できる対策としては,LISP ルーターか らの ICMP time-exceeded パケットの送信を禁止してしまう方法がある.これは ファイアーウォールを利用して,LISP ルーターとなるサーバー上で次のコマン ドを実行することで簡単に実行することが出来る. # iptables -A OUTPUT -p icmp --icmp-type time-exceeded -j DROP # ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type time-exceeded -j DROP 実行後の traceroute6 については以下のようになり,traceroute を実行しても経 路を認識することができなくなる.その他の通信については通常通りに行うこと が出来る. 41 traceroute to 2003::8801:203:278:156 (2003::8801:203:278:156) , 30 hops max, 80 byte packets 1 * * * 2 * * * 3 2003::8801:203:278:156 (2003::8801:203:278:156) 21.196 ms 21.138 ms 21.066 ms しかしこの方法による対応の場合,いくつか問題も考えられる. • 常に ICMP time-exceeded パケットを遮断してしまうのは,ネットワークの 管理者が管理する上で不便な場合がある. • 逆に 2-MapLISP を使用した時のみ遮断する場合,システム構成を秘匿する 効果はあるものの,攻撃者は少なくとも traceroute がまともにできなくな る何かを実行されたことは把握でき,完全な対処の秘匿に至らない可能性 がある. 上記のような問題が考えられるため,更なる課題として,これらに対応するこ とが挙げられる.方法としては,traceroute のパケット,すなわち TTL が 0 の ICMP echo request パケットや UDP パケットを受信した場合に,囮のルーター から内容を詐称したパケットを返させる方法がある.具体的には,囮のルーター が上記のようなパケットを受信した際に,攻撃サーバーから本来の被害サーバー に至る経路上の LISP ルーターからのものとして ICMP time-exceeded パケット を送信させるということである.ただし正確な traceroute の判別が求められる. traceroute で使用されるパケットは原理的には何でも良いが,主に使用される パケットとしては 2 種類存在し,TTL を 1 ずつ増やすことは共通するが,ICMP echo request パケットを使用する場合と UDP パケットを使用する場合がある.前 者は windows 系の OS で標準的に使われ,後者は Unix 系の OS で標準的に使わ れる.ICMP echo request パケットを利用した traceroute の場合は「ICMP echo request パケットのうち,TTL が 0 のもの」という条件となり,これだけで対象 をかなり限定することが可能であり,比較的容易に正確な判別ができると考えら れるが,UDP パケットを利用した traceroute の場合,UDP パケットという条件 では対象が多すぎるので,使用ポートやペイロード等,条件を増やして対象を絞 る必要がある. 42 しかし原理的にはこれら 2 種類のパケット以外を使用しても同じ効果を得るこ とが可能なことを考慮すれば,ここで述べた方針は一般的な traceroute への対策 に過ぎず,絶対的な対策ではないことは把握しておかねばならない.また,どの ようなパケットでも原理的に問題ないということは,絶対的な対策をすることは 困難ということである.従って,ICMP time-exceeded パケットの送信禁止も偽 装パケットの送信も,考えられる手法は全て併用して対策の精度を上げる必要が ある. この他,RTT の変化を見る事によっても経路が変更されたことを把握するきっ かけとすることができる.これへの対策としては,囮の付近に偽の経路をさらに 増やして調節する方法や,囮のルーターにパケットの転送を故意に遅延させる機 能を組み込む方法が考えられる.この場合,前者は特に機能を付ける必要もなく, 単に使用する LISP ルーターを増やすだけで実施できるものの,設置のコストが 増大することになるため,運用上好ましい方法ではなく,また場合によっては現 実的な時間で実施できない方法であるとも考えられる.従って実施するなら後者 の方が望ましい. 5.3 継続性の向上 本提案では被害サーバーを完全にコピーした囮サーバーに,被害サーバーと同 様の動作をさせることを想定しているが,4.1.1 項で示したように,経路変更した トラフィックの規模によっては輻輳し,応答の悪い状態となってしまう. こうした状況については,対処の方針はいくつか考えられる.ロードバランサー の使用等,既存の DDoS 攻撃対策手法と組み合わせ,あるいは囮の数を増やすこ とで負荷を分散し,処理がスムーズに行われるようにすることや,広帯域な回線 を使用したり囮サーバーの能力を高める等,関係する部分の処理能力を高めてや ることである.処理能力を高める方針に関してはこれに限らずあらゆる場面にお いて考えられる方法である.流入口ルーターの数を増やす方針に関しては EID に 対して複数の RLOC を設定できることを活かしている. その他に考えられる方針としては,そもそも囮サーバーをサービスを提供する ものと見なさず,壊れて良いものとして扱うことが考えられる.これはすなわち, 43 前二つがスムーズにサービスを提供するため負荷を分散したり処理能力を高めた りすることで対応するのに対して,これは攻撃成功を装い攻撃者を欺瞞するため にあえて囮を壊してしまうということである.場合によっては故意に処理能力を 低く設定したり,脆弱性を持たせることも考えられる. 前者と後者を比較すると,前者はサービスの提供を途切れさせないことに主眼 を置き,コストをかけてサーバーを保護する方法であるのに対し,後者は攻撃者 を欺いて攻撃終了を促してなるべく早期に平常時に戻してやることを目的とし て,故意に能力の低い囮を設置してサーバーを壊れやすい状態とし,攻撃成功を 演出する方法ということである.ただし後者はなるべく早期に平常時に戻す目的 があるとはいえ,当然ここで言うところのサービスの継続性は一時的には犠牲に される. 後者の方法の利点としては能力を高めて囮サーバーを保護する必要がないので, 前者に比べてコストを抑えながら対処することが可能であり,意図した通りに攻 撃が早期に終了すれば有効な対処であるということが言える.しかし注意すべき 点としては,攻撃成功を受けて意図した通りの早期に攻撃が終了するかどうかに ついては,攻撃者の判断次第であり,確実性に欠けるということである.極論す れば,例えばイデオロギーに基づく攻撃では考えにくいが,愉快犯的に攻撃を開 始したものの気まぐれに面倒になって終了してしまうケースも考えられるし,逆 に攻撃開始後しばらく放置してほとんど成否の確認を行わないケースも考えられ る.従って,この方針に基づいて囮を設置する場合は,これを絶対唯一の防御と するのではなく,既存の手法との組み合わせで実施したり,あるいはこの方針で 対処し,攻撃者の反応次第で前者の方法に切り替える等,柔軟に判断して対処す る必要がある. 5.4 対処完了時間について 本提案は単純に破棄,遮断するだけの方法と比して手間のかかる手法であるが, 企業アンケートの分析 [1] によれば,各対策手法の DDoS 攻撃対処が完了するま での時間について見てみると,早いものなら 10 分以内,長いものでも 30 分程度 で完了できるものが大半であるので,これを目安に完了できるようにしていく必 44 要がある. 経路の切り替え時間に関しては,囮の準備が出来てさえいれば LISP ルーター の再起動に要する 10 秒程度の時間しか必要としない.すなわち本提案を実行す る際に必要とする時間の大部分は囮サーバーの設置にかかる時間ということにな る.設置の方法としてはストレージを wget で入手させて仮想サーバーを立ち上 げさせる方法や,ストレージマイグレーションを利用する方法等が考えられるが, ストレージマイグレーションを使用する場合はマイグレーション終了後に元の仮 想サーバーを閉じさせないよう改変する必要がある. 対処完了時間を短縮する方針としては,囮サーバー設置の手間そのものを削減 することと,1 つの囮サーバーで対処する流入口の LISP ルーターの数を 1 つまで とせず,ホップ数や RTT を基準にある一定の範囲を対応させることで,設置数 を削減する方法が考えられる.後者については,局所化の効果と対応させる範囲 の広さはトレードオフの関係となり,メトリクスを作成して適切な関係を保ちな がら囮サーバーを設置する必要がある. 5.5 規模を拡大した際の適用について 規模を大きくした場合の適用について考察する必要がある.まず被害サーバー の所属する AS が地理的に狭い範囲しか管理しない,海外のネットワークへのリン クを持たないような場合を例にとって考える.このとき,遠く離れた海外にある ボットネットから DDoS 攻撃を仕掛けられたと想定すると,管理する地理的に範 囲の狭い AS 内で DoS パケットを囮サーバーに経路を曲げたところで,その AS の 外側を考えれば,局所化して経路上の DDoS 負荷を軽減できたとはいえない.経 路上の DDoS 負荷を軽減しようとしているので,パケットはなるべく少ないホッ プ数のうちに処理されなくてはならない.これに対して,単一の AS で地理的に広 い範囲を網羅できる AS を対象として考えると,AS 間の連携等を前提としなくて も,局所化という点に関して一定の効果を得ることができる.ただし,この場合 は流入口の LISP ルーターの数も増え,あらゆる方向から攻撃が流入してくるこ ととなる.その際は囮の LISP ルーターをそれに合わせて多数設置しなければな らなくなるが,その場合であっても現実的な時間で対処が完了できるようにする 45 必要がある.AS が地理的に狭い範囲しか管理できていない場合でも 2-MapLISP を適用するためには,AS 間で連携して対応する必要がある.すなわち,AS を越 えて囮サーバーを配置し,局所化を行う必要がある.しかしこれは,連携,協調 して対処を行っているという前提とはいえ,自分達が使用しているのと同様の能 力の囮サーバーを管理 AS の外へ設置することが必要ということであり,その安 全性をどのように確保するか考える必要がある. 5.6 再帰的問い合わせ DDoS 攻撃と反射型 DDoS 攻撃について 一般にイメージされる,ボットネットから大量のリクエストを送る DDoS 攻撃 とは別に,DNS の再帰的な問い合わせを悪用した DDoS 攻撃が存在する.これ は攻撃者が攻撃対象を装って DNS サーバーに問い合わせデータを送信すること で,DNS サーバーから攻撃対象に問い合わせデータの数十倍の応答データを送信 させるものであるが,この攻撃は 2-MapLISP に使用することのできる可能性が ある.通常の手順では,攻撃者が用意した DNS サーバーにサイズの大きい TXT レコードを用意し,攻撃者から踏み台とするキャッシュサーバーに対して用意し た TXT レコードに対する再帰的問い合わせを実施して,キャッシュサーバーに TXT レコードをキャッシュさせる.そして実際に攻撃する段階においては,攻撃 者は標的サーバーを装って踏み台のキャッシュサーバーに対して用意した TXT レ コードに対する再帰的問い合わせを実施することで,標的サーバーへキャッシュ サーバーからトラフィックを増幅して送られる.もし攻撃者に 2-MapLISP を把握 された場合,LISP ルーターをキャッシュサーバーと置き換え,この攻撃手法を実 施される可能性がある.また反射型 DDoS 攻撃という攻撃があるが,これは攻撃 者が攻撃対象の IP アドレスに偽装したパケットをリフレクタと呼ばれる踏み台 のサーバーに送信することで発生する.リフレクタはパケットを受け取り応答を 返すサーバーでさえあれば良く,この攻撃も 2-MapLISP に使用することのでき る可能性がある.すなわち,攻撃者が被害サーバーの EID とその LISP ルーター の RLOC を詐称できたとすれば使用できる.したがって,攻撃者に対策手法を認 識されないようにすることが重要であると同時に,把握された場合に備えて対策 すべきである.通常の対策では,信頼できる利用者以外からの再帰的問い合わせ 46 を受け付けないようにキャッシュサーバーを設定することや,レートリミットを 設定する等の工夫でトラフィックを増幅させないこと方法がとられる.これらの 対策を LISP ルーターにも組み込むべきである. 47 6. おわりに 本論文では,DDoS 攻撃を局所化し,攻撃と関係のないトラフィックに影響せ ずに,標的サーバーおよび標的サーバーに至る経路上の DDoS 負荷を軽減し,ま た対処後のシステム構成を秘匿して攻撃者に攻撃対処を認識させにくくする方法 について提案を行った. これを実現するため,LISP の特性に注目した.LISP は IP アドレスの機能を EID と RLOC の 2 つに分け,1 つの EID に対して複数の RLOC を登録できる特 性を持つので,これを利用して被害サーバーを複製した囮サーバーを設置し,ト ラフィックの局所化を図る.この際,EID と RLOC の対応関係を把握しているの はマップサーバーだけであり,攻撃者は誰に向けて通信しているかは認識できる が,どこに向けて通信しているか,通信相手の場所については認識できないため, 囮サーバーへと通信経路が変更されたことを認識できない.ただし LISP の従来 の機能だけでは特定の通信元のみを囮へと結びつけるルーティングはできないた め,そのための機能を組み込んだ. これについて実験を行い,各種リソースの消費を強要されるような高負荷環境 においても提案が実行可能であることを確認した.今後は規模を拡大した実験を 行い,実環境での適用を目指すとともに,各課題の解決を図る. 48 謝辞 本研究にわたる全過程を通じて,懇切なる御指導,御鞭撻を賜りました本学情 報科学研究科の山口英教授,藤川和利教授並びに門林雄基准教授に厚く感謝の意 を表します. 本研究を進めるにあたり奥田剛特任准教授,樫原茂助教,櫨山寛章助教には様々 な意見を頂き誠にありがとうございました.また,岡田和也さん,榎本真俊さん 並びに慶應義塾大学環境情報学部の上野幸杜さんには本研究における実験,実装 に大いにお力添えを頂き,お礼を申し上げます.研究の際,インターネット工学 研究室の皆様には大変お世話になりました. 49 参考文献 [1] R. Dobbins and C. Morales: “Worldwide Infrastructure Security Report”, Arbor Networks Technical Report (2012). [2] SPIRENT: “SPIRENT AVALANCHE SCALABLE APPLICATION PROTOCOL EMULATION ENGINE (SAPEE)”, Avalanche SAPEE datasheet (2012). [3] N. Hachem, Y. B. Mustapha, G. G. Granadillo and H. Debar: “Botnets: Lifecycle and Taxonomy”, Network and Information Systems Security (SARSSI), 2011 Conference on (2011). [4] Cisco Systems: “Defeating DDOS Attacks”, Cisco Systems Technical Report (2007). [5] http://www.gnu.org/software/mcron/. [6] T. Peng, C. Leckie and K. Ramamohanarao: “Survey of network-based defense mechanisms countering the DoS and DDoS problems”, ACM Computing Surverys, 39, 1 (2007). [7] 上野幸杜, 堀場勝広, 片岡広太郎:“ソフトウェア LISP ルータの設計と実装 ”, インターネットコンファレンス 2011 (IC2011)- Work in Progress (2011). [8] Frost & Sullivan: “Why Anti-DDoS Products and Services are Critical for Today’s Business Environment”, Frost & Sullivan Technical Report (2012). [9] A. C. Snoeren, C. Partridge, L. A. Sanches, C. EJones, F. Tchakountio, S. T. Kent and W. T. Stayer: “Hash-based IP traceback”, Proceedings of the 2001 conference on applications,technologies, architectures, and protocols for computer communications, ACM Press, pp. 3–14 (2001). [10] K. Scarfone and P. Mell: “Guide to Intrusion Detection and Prevention Systems (IDPS)”, NIST SP800-94 (2007). 50 [11] D. Farinacci, V. Fuller, D. Meyer and D. Lewis: “Locator/ID Separation Protocol (LISP)”, IETF Internet-Draft (2012). [12] J. Mirkovic and P. Reiher: “A taxonomy of DDoS attack and DDoS defense mechanisms”, SIGCOMM Comput. Commun. Rev., 34, 2, pp. 39–53 (2004). [13] D. Farinacci and D. Meyer: “LISP Canonical Address Format (LCAF)”, IETF Internet-Draft (2012). [14] V. Fuller and D. Farinacci: “LISP Map Server Interface” (2012). [15] エリック, 大, 仁, 明憲:“Moving Firewall における DDoS 攻撃対策システム の評価”, 電子情報通信学会技術研究報告. NS, ネットワークシステム (2002). [16] N. McKeown, T. Anderson, H. Balakrishnan, G. Parulkar, L. Peterson, J. Rexford, S. Shenker and J. Turner: “OpenFlow: enabling innovation in campus networks”, SIGCOMM Comput. Commun. Rev., 38, 2, pp. 69–74 (2008). [17] J. H. Jafarian, E. Al-Shaer and Q. Duan: “OpenFlow Random Host Mutation: Transparent Moving Target Defense using Software Defined Networking”, HotSDN ’12 Proceedings of the first workshop on Hot topics in software defined networks (2012). [18] 警察庁:“DNS の再帰的な問い合わせを悪用した DDoS 攻撃手法の検証につ いて” (2006). [19] V. Paxson: “An analysis of using reflectors for distributed denial-of-service attacks”, SIGCOMM Comput. Commun. Rev., 31, 3, pp. 38–47 (2001). [20] D. Mills: “Internet Time Synchronization: The Network Time Protocol”, RFC 1129 (Informational) (1989). 51 [21] P. Ferguson and D. Senie: “Network Ingress Filtering: Defeating Denial of Service Attacks which employ IP Source Address Spoofing”, RFC 2827 (Best Current Practice) (2000). Updated by RFC 3704. [22] T. Killalea: “Recommended Internet Service Provider Security Services and Procedures”, RFC 3013 (Best Current Practice) (2000). [23] D. Harrington, R. Presuhn and B. Wijnen: “An Architecture for Describing Simple Network Management Protocol (SNMP) Management Frameworks”, RFC 3411 (INTERNET STANDARD) (2002). Updated by RFCs 5343, 5590. [24] F. Baker and P. Savola: “Ingress Filtering for Multihomed Networks”, RFC 3704 (Best Current Practice) (2004). [25] D. Turk: “Configuring BGP to Block Denial-of-Service Attacks”, RFC 3882 (Informational) (2004). [26] W. Kumari and D. McPherson: “Remote Triggered Black Hole Filtering with Unicast Reverse Path Forwarding (uRPF)”, RFC 5635 (Informational) (2009). [27] D. Farinacci, V. Fuller, D. Meyer and D. Lewis: “The Locator/ID Separation Protocol (LISP)”, RFC 6830 (Experimental) (2013). [28] S. Savage, D. Wetherall, A. Karlin and T. Anderson: “Practical Network Support for IP traceback”, Proceedings of the conference on Applications,Technologies, Architectures, and Protocols for Computer Communication(SIGCOMM ’00), pp. 295–306 (2000). [29] B. Lantz, B. Heller and N. McKeown: “A Network in a Laptop: Rapid Prototyping for Software-Defined Networks”, Hotnets-IX Proceedings of the 9th ACM SIGCOMM Workshop on Hot Topics in Networks (2010). 52 [30] The Net-SNMP project: “Net-SNMP”, http://www.net-snmp.org/. [31] U. K. Tupakula and V. Varadharajan: “Analysis of traceback techniques”, Proceedings of the 2006 Australasian workshops on Grid computing and e-research - Volume 54 (2012). [32] 磯原隆将, 窪田歩, 三宅優:“大規模自律分散型ファイアウォールを用いた DDoS 攻撃防御”, 電子情報通信学会技術研究報告. ICSS, 情報通信システム セキュリティ, 109, 476, pp. 19–24 (2010). 53 付録 A. 拡張マップサーバーのソースコード A.1 main.c #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include <stdio.h> <stdlib.h> <string.h> <assert.h> <err.h> <unistd.h> <sys/types.h> <sys/ioctl.h> <fcntl.h> <arpa/inet.h> <net/if.h> <netinet/ip.h> <netinet/ip6.h> <net/ethernet.h> <openssl/hmac.h> <pthread.h> <syslog.h> <err.h> #include #include #include #include <termios.h> <sys/socket.h> <netinet/in.h> <netdb.h> #include #include #include #include "main.h" "route.h" "reply.h" "utils.h" char client_addr[100];//外部変数 struct elm ipv4_start; struct elm ipv6_start; pthread_t thread_id_ipv4_ttl; pthread_t thread_id_ipv6_ttl; struct sockaddr_in6 client; socklen_t sin_size = sizeof(client); int udp_sock; struct localize_list *localize = NULL; // 局所化リストに要素を追加する struct localize_list *list_add(struct localize_list *localize, char add_Attack_RLOC[], char add_Victim_EID[], char add_Decoy_RLOC[]){ struct localize_list *localize_list = (struct localize_list *)malloc(sizeof(struct localize_list));// 新しい要素を作成 strcpy(localize_list->Attack_RLOC , add_Attack_RLOC); strcpy(localize_list->Victim_EID , add_Victim_EID); strcpy(localize_list->Decoy_RLOC , add_Decoy_RLOC); localize_list->proposal_next = NULL;// 次の要素がないことを示すために NULL を代入 if(localize == NULL){ return localize_list;// リストが空の場合は特別扱いする }else{ struct localize_list *tail = localize;// リストの末尾の要素を探す (変数 tail は末尾の要素をさす) while(tail->proposal_next != NULL) tail = tail->proposal_next; tail->proposal_next = localize_list; return localize; 54 } free(localize_list); } //リストの削除。 //struct localize_list *deletelist(struct localize_list *localize, char del_Attack_RLOC[], char del_Victim_EID[], char del_Decoy_RLOC[]){ int deletelist(struct localize_list *localize, char del_Attack_RLOC[], char del_Victim_EID[], char del_Decoy_RLOC[]){ struct localize_list *p;//, *q; int delcmp = 0; p = localize; while(1){ delcmp = strcmp(del_Decoy_RLOC, localize->Decoy_RLOC); if(delcmp != 0){ p = localize; if( localize->proposal_next == NULL ){ /* 一致する値がないままリストの末尾まで来た */ // puts( "指定された要素はリスト内に存在しません" ); // break; return 0; } if(localize->proposal_next != NULL) localize = localize->proposal_next; /* 次の要素へ進む */ }else if(delcmp == 0){ if(localize->proposal_next != NULL){ p->proposal_next = localize->proposal_next; free(localize); break; }else{ p->proposal_next = localize->proposal_next; p->proposal_next = NULL; free(localize); break; } } } return 1; } // 表示 void display(struct localize_list *localize){ while(1){ printf("%s || %s || %s\n",localize->Attack_RLOC,localize->Victim_EID,localize->Decoy_RLOC); if(localize->proposal_next == NULL) break; localize = localize->proposal_next; } } int main(int argc, char * argv[]){ struct sockaddr_in6 me; char buf[2000]; int readsize; struct common_header *common; int d_flag = 0; char ch; char command; int d_list = 0; int receive_ipv4_i = 0; int receive_ipv6_i = 0; char *op_attack_rloc,*op_victim_eid,*op_decoy_rloc; char *oar,*ove,*odr; char *del_decoy_rloc; char *delete_RLOC; char *proposal_ntop_ar,*proposal_ntop_ve,*proposal_ntop_dr; char *proposal_ntop_deldr; unsigned char p_a; unsigned char *proposal_addr; proposal_addr = &p_a; op_attack_rloc = (char *)malloc(100);//scanf で入力したものを格納するためのメモリ確保 55 op_victim_eid = (char *)malloc(100); op_decoy_rloc = (char *)malloc(100); del_decoy_rloc = (char *)malloc(100); oar = (char *)malloc(100); ove = (char *)malloc(100); odr = (char *)malloc(100); delete_RLOC = (char *)malloc(100); proposal_ntop_ar = (char *)malloc(100); proposal_ntop_ve = (char *)malloc(100); proposal_ntop_dr = (char *)malloc(100); proposal_ntop_deldr = (char *)malloc(100); memset( memset( memset( memset( memset( memset( memset( memset( memset( memset( memset( memset( op_attack_rloc, ’\0’, 100);//malloc で確保したメモリ初期化 op_victim_eid, ’\0’, 100); op_decoy_rloc, ’\0’, 100); del_decoy_rloc, ’\0’, 100); oar, ’\0’, 100); ove, ’\0’, 100); odr, ’\0’, 100); delete_RLOC, ’\0’, 100); proposal_ntop_ar, ’\0’, 100); proposal_ntop_ve, ’\0’, 100); proposal_ntop_dr, ’\0’, 100); proposal_ntop_deldr, ’\0’, 100); while ((ch = getopt (argc, argv, "d")) != -1) { switch (ch) { case ’d’ : d_flag = 1; break; default : break; } } /* run as a daemon */ if (d_flag > 0) { if (daemon (0, 0) != 0) err (EXIT_FAILURE, "fail to run as a daemon\n"); } memset(&ipv4_start, 0, sizeof(struct elm)); memset(&ipv6_start, 0, sizeof(struct elm)); sin_size = sizeof(client); /* dualstack control-plane socket */ memset(&me, 0, sizeof(me)); me.sin6_family = AF_INET6; me.sin6_port = htons(4342); me.sin6_addr = in6addr_any; udp_sock = ipv6_create_sock(); if(udp_sock < 0) { perror("socket"); exit(1); } if(bind(udp_sock, (struct sockaddr *)&me, sizeof(me)) < 0){ perror("ipv6 bind"); exit(1); } /* start IPv4 TTL timer */ if (pthread_create(&thread_id_ipv4_ttl, NULL, ipv4_rem_list_by_ttl, NULL) != 0 ){ exit(1); } 56 /* start IPv6 TTL timer */ if (pthread_create(&thread_id_ipv6_ttl, NULL, ipv6_rem_list_by_ttl, NULL) != 0 ){ exit(1); } /* regist static route for debug */ //リストに初期値を入れる。初期値がないとエラーになる。 ipv4_regist_static_entry("8.0.0.0", 8, "8.8.8.8", 3600);//通常の LISP の初期値 strcpy(op_attack_rloc,"ffff::eeee");//提案手法の初期値 strcpy(op_victim_eid,"dddd::cccc"); strcpy(op_decoy_rloc,"bbbb::abcd"); inet_pton(AF_INET6,op_attack_rloc,proposal_addr); inet_ntop(AF_INET6,proposal_addr,proposal_ntop_ar,100); strcpy(oar,proposal_ntop_ar); free(op_attack_rloc);//malloc で確保した領域を解放 free(proposal_ntop_ar); inet_pton(AF_INET6,op_victim_eid,proposal_addr); inet_ntop(AF_INET6,proposal_addr,proposal_ntop_ve,100); strcpy(ove,proposal_ntop_ve); free(op_victim_eid); free(proposal_ntop_ve); inet_pton(AF_INET6,op_decoy_rloc,proposal_addr); inet_ntop(AF_INET6,proposal_addr,proposal_ntop_dr,100); strcpy(odr,proposal_ntop_dr); free(op_decoy_rloc); free(proposal_ntop_dr); localize = list_add(localize,oar,ove,odr);//初期値を局所化リストに入れる free(oar); free(ove); free(odr);//ここまでリストの初期値を入れる部分 while(1){ memset(buf, 0, sizeof(buf)); memset(&client, 0, sizeof(struct sockaddr_in6)); printf("リスト操作は Enter を押してください\n"); readsize = recvfrom(udp_sock, buf, sizeof(buf), 0, (struct sockaddr *)&client, &sin_size);//recvfrom で待ち受けになる // printf("test1\n"); if(readsize<0){ err(EXIT_FAILURE, "read failed"); } if(client.sin6_family == AF_INET){ receive_ipv4_i++; printf("%d 回目 v4 パケット受信\n",receive_ipv4_i); inet_ntop(AF_INET, &(client.sin6_addr), client_addr, 100); }else if(client.sin6_family == AF_INET6){ receive_ipv6_i++; printf("%d 回目 v6 パケット受信\n",receive_ipv6_i); inet_ntop(AF_INET6, &(client.sin6_addr), client_addr, 100); } horder(buf, readsize); common = (struct common_header *)buf; if(common->TYPE == 3){ syslog_write(LOG_INFO, "map-regist: packet received %d byte from %s", readsize, client_addr); parse_register_header(buf, readsize); printf("register"); printf("クライアントアドレス%s\n",client_addr); memset(buf,0,sizeof(buf)); }else if(common->TYPE == 1){ syslog_write(LOG_INFO, "map-request: packet received %d byte from %s", readsize, client_addr); parse_request_header(buf, readsize); 57 printf("request"); printf("クライアントアドレス%s\n",client_addr); memset(buf,0,sizeof(buf)); }else if(common->TYPE == 8){ syslog_write(LOG_INFO, "encapsulated control message: packet received %d byte from %s", readsize, client_addr); decap_control_message(buf, readsize); printf("decap"); printf("クライアントアドレス%s\n",client_addr); memset(buf,0,sizeof(buf)); } //提案のリスト作成(手入力) if (kbhit()) { //何かキーボード入力すると提案手法に移行 while(1){ while (getchar() != ’\n’){ }//キーバッファを空にする op_attack_rloc = (char *)malloc(100);//scanf で入力したものを格納するためのメモリ確保 op_victim_eid = (char *)malloc(100); op_decoy_rloc = (char *)malloc(100); del_decoy_rloc = (char *)malloc(100); oar = (char *)malloc(100); ove = (char *)malloc(100); odr = (char *)malloc(100); delete_RLOC = (char *)malloc(100); proposal_ntop_ar = (char *)malloc(100); proposal_ntop_ve = (char *)malloc(100); proposal_ntop_dr = (char *)malloc(100); proposal_ntop_deldr = (char *)malloc(100); memset( memset( memset( memset( memset( memset( memset( memset( memset( memset( memset( memset( op_attack_rloc, ’\0’, 100);//メモリ初期化 op_victim_eid, ’\0’, 100); op_decoy_rloc, ’\0’, 100); del_decoy_rloc, ’\0’, 100); oar, ’\0’, 100); ove, ’\0’, 100); odr, ’\0’, 100); delete_RLOC, ’\0’, 100); proposal_ntop_ar, ’\0’, 100); proposal_ntop_ve, ’\0’, 100); proposal_ntop_dr, ’\0’, 100); proposal_ntop_deldr, ’\0’, 100); //リストの削除と追加 printf("\n 局所化リストの今の状態\n"); printf("流入口ルーター RLOC || 被害 EID || 囮ルーター RLOC\n"); display(localize);//局所化リストの今の状態を表示 printf("\n リストの削除なら d を入力して Enter、追加はそのまま Enter を押してください\n"); scanf( "%c", &command ); if(command == ’d’){ printf("削除したい囮 RLOC 入力:"); if(scanf("%s",del_decoy_rloc)!=1) scanf("%*s"); while (getchar() != ’\n’) { } inet_pton(AF_INET6,del_decoy_rloc,proposal_addr); inet_ntop(AF_INET6,proposal_addr,proposal_ntop_deldr,100); strcpy(delete_RLOC,proposal_ntop_deldr); free(del_decoy_rloc); free(proposal_ntop_deldr); while(1){ // localize = deletelist(localize,0,0,delete_RLOC); d_list = deletelist(localize,0,0,delete_RLOC); if(d_list == 0) break; } printf("\n 局所化リスト表示\n"); printf("流入口ルーター RLOC || 被害 EID || 囮ルーター RLOC\n"); display(localize);//局所化リストの今の状態を表示 // printf("\n 何かキーを押してください\n"); 58 // getchar();//何かキーを押すまでループを待機 }else{ printf("流入口 RLOC 入力:"); if(scanf("%s",op_attack_rloc)!=1) scanf("%*s");//予期しないものは読み飛ばす while (getchar() != ’\n’) { }//scanf のバッファを空にする inet_pton(AF_INET6,op_attack_rloc,proposal_addr); inet_ntop(AF_INET6,proposal_addr,proposal_ntop_ar,100); strcpy(oar,proposal_ntop_ar); free(op_attack_rloc);//malloc で確保した領域を解放 free(proposal_ntop_ar); printf("被害 EID 入力:"); if(scanf("%s",op_victim_eid)!=1) scanf("%*s"); while (getchar() != ’\n’) { } inet_pton(AF_INET6,op_victim_eid,proposal_addr); inet_ntop(AF_INET6,proposal_addr,proposal_ntop_ve,100); strcpy(ove,proposal_ntop_ve); free(op_victim_eid); free(proposal_ntop_ve); printf("囮 RLOC 入力:"); if(scanf("%s",op_decoy_rloc)!=1) scanf("%*s"); while (getchar() != ’\n’) { } inet_pton(AF_INET6,op_decoy_rloc,proposal_addr); inet_ntop(AF_INET6,proposal_addr,proposal_ntop_dr,100); strcpy(odr,proposal_ntop_dr); free(op_decoy_rloc); free(proposal_ntop_dr); // localize = list_add(localize,oar,ove,odr);//入力した各要素を局所化リストに入れる list_add(localize,oar,ove,odr); free(oar); free(ove); free(odr); printf("\n 局所化リスト表示\n"); printf("流入口ルーター RLOC || 被害 EID || 囮ルーター RLOC\n"); display(localize);//局所化リストの今の状態を表示 // printf("\n 何かキーを押してください\n"); // getchar();//何かキーを押すまでループを待機 } printf("\n 何かキーを押してください\n"); while (getchar() != ’\n’){ } printf("\nEnter でリスト作成に戻る。e を入力して Enter でリスト作成終了\n"); scanf( "%c", &command ); if(command == ’e’){ while (getchar() != ’\n’){ } break; } }//ここまで提案のリスト作成 } } } /* authentication HMAC-SHA-1 */ int auth_reg_packet(void *buf, size_t size, int auth_len, char *auth_data){ char key[] = AUTH_KEY; size_t keylen = strlen(key); size_t reslen; char *result = malloc(auth_len); memset(result, 0, auth_len); HMAC(EVP_sha1(), key, keylen, buf, size, result, (unsigned int *)&reslen); if(!memcmp(auth_data, result, auth_len)){ 59 syslog_write(LOG_INFO, "map-regist: authentication success"); free(result); return SUCCESS; }else{ syslog_write(LOG_INFO, "map-regist: authentication failure"); free(result); return FAILURE; } } void parse_register_header(char *buf, int readsize){ char *ptr; int data_len; int auth_len; struct reg_header *h = (struct reg_header *)buf; int i, size = 0; auth_len = h->AUTH_DATA_LENGTH; ptr = buf + 16 + auth_len; data_len = readsize - (16 + auth_len); char *auth_data = malloc(auth_len); memcpy(auth_data, buf + sizeof(struct reg_header), auth_len); norder(auth_data, auth_len); memset(buf + sizeof(struct reg_header), 0, auth_len); norder(buf, readsize); if(auth_reg_packet(buf, readsize, auth_len, auth_data) == FAILURE){ free(auth_data); return; }else{ free(auth_data); } horder(buf, readsize); for(i = 0; i < h->REC_COUNT; i++){ size += parse_register_data((ptr + size), data_len); } } int parse_register_data(char *buf, int data_len){ /* NOT SUPPORTED MULTIPLE LOCATOR */ union reg_data *d; d = (union reg_data *)buf; char network[16]; int prefix; char rloc[16]; int af; memset(network, 0, 16); memset(rloc, 0, 16); if(d->d66.EID_AFI == 2){ if(d->d66.LOC_AFI == 2){ /* data66 */ af = 2; prefix = d->d66.EID_MASKLEN; norder(d->d66.EID_PREFIX, 16); memcpy(network, d->d66.EID_PREFIX, 16); norder(d->d66.LOCATER, 16); memcpy(rloc, d->d66.LOCATER, 16); /* for syslog */ char log_eid_addr[100]; char log_rloc_addr[100]; 60 inet_ntop(AF_INET6, network, log_eid_addr, 100); inet_ntop(AF_INET6, rloc, log_rloc_addr, 100); syslog_write(LOG_INFO, "map-regist: %s/%d -> %s ttl %d minutes", log_eid_addr, prefix, log_rloc_addr, d->d66.TTL); regist_prefix(&ipv6_start, network, prefix, rloc, af, d->d66.TTL); struct info *newroute = malloc(sizeof(struct info)); memset(newroute, 0, sizeof(struct info)); memcpy(newroute->address, network, 16); newroute->prefix = prefix; newroute->ttl = d->d66.TTL * 60; ipv6_add_list(newroute); return sizeof(struct reg_data66); }else if(d->d66.LOC_AFI == 1){ /* data64 */ af = 1; prefix = d->d64.EID_MASKLEN; norder(d->d64.EID_PREFIX, 16); memcpy(network, d->d64.EID_PREFIX, 16); norder(d->d64.LOCATER, 4); memcpy(rloc, d->d64.LOCATER, 4); /* for syslog */ char log_eid_addr[100]; char log_rloc_addr[100]; inet_ntop(AF_INET6, network, log_eid_addr, 100); inet_ntop(AF_INET, rloc, log_rloc_addr, 100); syslog_write(LOG_INFO, "map-regist: %s/%d -> %s ttl %d minutes", log_eid_addr, prefix, log_rloc_addr, d->d64.TTL); regist_prefix(&ipv6_start, network, prefix, rloc, af, d->d64.TTL); struct info *newroute = malloc(sizeof(struct info)); memset(newroute, 0, sizeof(struct info)); memcpy(newroute->address, network, 16); newroute->prefix = prefix; newroute->ttl = d->d64.TTL * 60; ipv6_add_list(newroute); return sizeof(struct reg_data64); } }else if(d->d66.EID_AFI == 1){ if(d->d46.LOC_AFI == 2){ /* data46 */ af = 2; prefix = d->d46.EID_MASKLEN; norder(d->d46.EID_PREFIX, 4); memcpy(network, d->d46.EID_PREFIX, 4); norder(d->d46.LOCATER, 16); memcpy(rloc, d->d46.LOCATER, 16); /* for syslog */ char log_eid_addr[100]; char log_rloc_addr[100]; inet_ntop(AF_INET, network, log_eid_addr, 100); inet_ntop(AF_INET6, rloc, log_rloc_addr, 100); syslog_write(LOG_INFO, "map-regist: %s/%d -> %s ttl %d minutes", log_eid_addr, prefix, log_rloc_addr, d->d46.TTL); regist_prefix(&ipv4_start, network, prefix, rloc, af, d->d46.TTL); struct info *newroute = malloc(sizeof(struct info)); memset(newroute, 0, sizeof(struct info)); memcpy(newroute->address, network, 16); newroute->prefix = prefix; newroute->ttl = d->d46.TTL * 60; 61 ipv4_add_list(newroute); return sizeof(struct reg_data46); }else if(d->d46.LOC_AFI == 1){ /* data44 */ af = 1; prefix = d->d44.EID_MASKLEN; norder(d->d44.EID_PREFIX, 4); memcpy(network, d->d44.EID_PREFIX, 4); norder(d->d44.LOCATER, 4); memcpy(rloc, d->d44.LOCATER, 4); /* for syslog */ char log_eid_addr[100]; char log_rloc_addr[100]; inet_ntop(AF_INET, network, log_eid_addr, 100); inet_ntop(AF_INET, rloc, log_rloc_addr, 100); syslog_write(LOG_INFO, "map-regist: %s/%d -> %s ttl %d minutes", log_eid_addr, prefix, log_rloc_addr, d->d44.TTL); regist_prefix(&ipv4_start, network, prefix, rloc, af, d->d44.TTL); struct info *newroute = malloc(sizeof(struct info)); memset(newroute, 0, sizeof(struct info)); memcpy(newroute->address, network, 16); newroute->prefix = prefix; newroute->ttl = d->d44.TTL * 60; ipv4_add_list(newroute); return sizeof(struct reg_data44); } } } void ipv4_regist_static_entry(char *networkstr, int prefix, char *nexthopstr, int ttl){ struct in_addr network; struct in_addr nexthop; memset((char *)&network, 0, sizeof(struct in_addr)); memset((char *)&nexthop, 0, sizeof(struct in_addr)); inet_pton(AF_INET, networkstr, &network); inet_pton(AF_INET, nexthopstr, &nexthop); regist_prefix(&ipv4_start, (char *)&(network.s_addr), prefix, (char *)&(nexthop.s_addr), 1, 60); struct info *newroute = malloc(sizeof(struct info)); memset(newroute, 0, sizeof(struct info)); memcpy(newroute->address, (char *)&(network.s_addr), 4); newroute->prefix = prefix; newroute->ttl = ttl; ipv4_add_list(newroute); } void decap_control_message(char *buf, int readsize){ char *ptr = buf; struct ipv6_common_header *iph; int size = readsize; /* cut lisp header */ ptr = ptr + 4; size -= 4; /* cut inner ip header */ iph = (struct ipv6_common_header *)ptr; if(iph->VERSION == 4){ ptr = ptr + 20; size -= 20; }else if(iph->VERSION == 6){ ptr = ptr + 40; 62 size -= 40; }else{ /* invalid packet */ return; } /* cut inner udp header */ ptr = ptr + 8; size -= 8; syslog_write(LOG_INFO, "encapsulated control message: %d bytes decapsulated", readsize - size); parse_request_header(ptr, size); } int kbhit(void){ struct termios oldt, newt; // int ch; char ch; int oldf; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); ch = getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); fcntl(STDIN_FILENO, F_SETFL, oldf); //while (getchar() != ’\n’){ } if (ch != EOF) { ungetc(ch, stdin); return 1; } return 0; } 63 A.2 main.h #define #define #define #define #define #define extern extern extern extern extern SERV_MODE 6 SUCCESS 0 FAILURE 1 AUTH_KEY "marutaka" LOG_FACILITY LOG_LOCAL3 PROCESS_NAME "mapserver" struct elm ipv4_start; struct elm ipv6_start; struct sockaddr_in6 client; socklen_t sin_size; int udp_sock; // 提案手法で使う局所化リストの構造体の定義 struct localize_list { char Attack_RLOC[100]; char Victim_EID[100]; char Decoy_RLOC[100]; struct localize_list *proposal_next; // localize_list へのポインタ }; struct localize_list *localize; struct common_header { __u32 REC_COUNT : 8, RESERVED : 19, P : 1, TYPE : 4; }; struct ipv6_common_header { __u32 FLOW_LABEL : 20, TRAFFIC_CLASS : 8, VERSION : 4; }; struct reg_header { __u32 char __u32 REC_COUNT : 8, RESERVED : 19, P : 1, TYPE : 4; NONCE[8]; AUTH_DATA_LENGTH : 16, KEY_ID : 16; }; struct reg_data66 { __u32 char __u32 char TTL, RESERVED : 12, A : 1, ACT : 3, EID_MASKLEN : 8, LOC_COUNT : 8, EID_AFI : 16, MAP_VERSION_NUM : 12, RSVD : 4; EID_PREFIX[16]; M_WEIGHT : 8, M_PRIORITY : 8, WEIGHT : 8, PRIORITY : 8, LOC_AFI : 16, R : 1, P : 1, L : 1, UNUSED_FLAGS : 13; LOCATER[16]; }; 64 struct reg_data64 { __u32 char __u32 char TTL, RESERVED : 12, A : 1, ACT : 3, EID_MASKLEN : 8, LOC_COUNT : 8, EID_AFI : 16, MAP_VERSION_NUM : 12, RSVD : 4; EID_PREFIX[16]; M_WEIGHT : 8, M_PRIORITY : 8, WEIGHT : 8, PRIORITY : 8, LOC_AFI : 16, R : 1, P : 1, L : 1, UNUSED_FLAGS : 13; LOCATER[4]; }; struct reg_data46 { __u32 char __u32 char TTL, RESERVED : 12, A : 1, ACT : 3, EID_MASKLEN : 8, LOC_COUNT : 8, EID_AFI : 16, MAP_VERSION_NUM : 12, RSVD : 4; EID_PREFIX[4]; M_WEIGHT : 8, M_PRIORITY : 8, WEIGHT : 8, PRIORITY : 8, LOC_AFI : 16, R : 1, P : 1, L : 1, UNUSED_FLAGS : 13; LOCATER[16]; }; struct reg_data44 { __u32 char __u32 char TTL, RESERVED : 12, A : 1, ACT : 3, EID_MASKLEN : 8, LOC_COUNT : 8, EID_AFI : 16, MAP_VERSION_NUM : 12, RSVD : 4; EID_PREFIX[4]; M_WEIGHT : 8, M_PRIORITY : 8, WEIGHT : 8, PRIORITY : 8, LOC_AFI : 16, R : 1, P : 1, L : 1, UNUSED_FLAGS : 13; LOCATER[4]; }; 65 union reg_data struct struct struct struct }; { reg_data66 reg_data64 reg_data46 reg_data44 d66; d64; d46; d44; void parse_register_header(char *buf, int readsize); int parse_register_data(char *buf, int data_len); void decap_control_message(char *buf, int readsize); void ipv4_regist_static_entry(char *networkstr, int prefix, char *nexthopstr, int ttl); int auth_reg_packet(void *buf, size_t size, int auth_len, char *auth_data); struct localize_list *list_add(struct localize_list *localize, char add_Attack_RLOC[], char add_Victim_EID[], char add_Decoy_RLOC[]); void display(struct localize_list *localize); int kbhit(void); 66 A.3 reply.c #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include <stdio.h> <stdlib.h> <string.h> <assert.h> <err.h> <unistd.h> <sys/types.h> <sys/ioctl.h> <fcntl.h> <arpa/inet.h> <net/if.h> <netinet/ip.h> <netinet/ip6.h> <net/ethernet.h> <syslog.h> <err.h> #include #include #include #include <termios.h> <sys/socket.h> <netinet/in.h> <netdb.h> #include <stdint.h> #include #include #include #include "main.h" "route.h" "reply.h" "utils.h" extern char client_addr[100];//外部変数 int check_v4; //char print_eid[100]; int check_list(struct localize_list *localize, char eid_print[],char returnrloc[],char returneid[]){//提案手法に入るか判断するための 関数 //int check_list(struct localize_list *localize,char returnrloc[],char returneid[]){ int attack_cmp,victim_cmp; int check_list_count = 0; printf("局所化リストの検査開始\n"); while(1){ check_list_count++; attack_cmp = strcmp(localize->Attack_RLOC , client_addr); // victim_cmp = strcmp(localize->Victim_EID , print_eid); victim_cmp = strcmp(localize->Victim_EID , eid_print); // printf("client_addr == %s, print_eid == %s,\n", client_addr, print_eid); printf("client_addr == %s, print_eid == %s,\n", client_addr, eid_print); if(attack_cmp == 0){ if(victim_cmp == 0){ printf("局所化リストに該当あり\n"); strcpy(returneid,localize->Victim_EID);//局所化リストとリクエストが一致したので、被害 EID と囮の RLOC を取り出す strcpy(returnrloc,localize->Decoy_RLOC); printf("リストの%d 行目、Decoy_RLOC == %s を使う\n", check_list_count, localize->Decoy_RLOC); check_list_count = 0; // memset(print_eid, ’\0’, 100); return 1; break; } } if(localize->proposal_next == NULL){ printf("局所化リストと一致しなかった\n"); check_list_count = 0; // memset(print_eid, ’\0’, 100); return 0; } localize = localize->proposal_next; printf("%d 行目は該当なし\n",check_list_count); } 67 } void send_reply_packet(char *packet, int size){ int send_size; send_size = sendto(udp_sock, packet, size, 0, (struct sockaddr *)&client, sin_size); if(send_size == -1){ perror("send"); exit(1); } syslog_write(LOG_INFO, "map-reply: %d byte reply packet sent", send_size); printf("パケット送信\n"); } void create_reply_packet(char *request_eid, int request_prefix, int request_af, char *nonce){ struct rep_mes reply; int reply_af; int prefix; int size = 0; int ttl; char nexthop[16]; char print_eid[100]; char nexthop_i[100]; memset(nexthop_i,0,100); char eidrequest_i[100]; memset(print_eid, ’\0’, 100); memset(&reply, 0, sizeof(struct rep_mes)); // printf("request_eid == %s\n",request_eid); // printf("request_prefix == %d\n",request_prefix); // printf("ipv6_start->af, flag, ttl == %d, %d, %d\n",ipv6_start.af, ipv6_start.flag, ipv6_start.ttl); //printf("request_af == %s\n",request_af); if(request_af == 2){ prefix = match_dst_with_limit(&ipv6_start, request_eid, nexthop, &reply_af, &ttl, request_prefix); }else if(request_af == 1){ prefix = match_dst_with_limit(&ipv4_start, request_eid, nexthop, &reply_af, &ttl, request_prefix); } inet_ntop(AF_INET, nexthop, nexthop_i, 100); // printf("prefix == %d, nexthop == %s\n",prefix, nexthop_i); inet_ntop(AF_INET6, request_eid, print_eid, 100); int list_check; char return_list_decoy_rloc[100]; char return_list_victim_eid[100]; memset(return_list_decoy_rloc,’\0’,100); memset(return_list_victim_eid,’\0’,100); list_check = check_list(localize,print_eid,return_list_decoy_rloc,return_list_victim_eid);//この関数の戻り値で提案手法を使うか判断す る。同時に当該の囮 RLOC を受け取る。 // list_check = check_list(localize,return_list_decoy_rloc,return_list_victim_eid); // printf("return_list_decoy_rloc == %s\n",return_list_decoy_rloc); // memset(print_eid, ’\0’, 100); if(list_check == 1){ printf("クライアントはアタッカーである\n"); printf("囮の RLOC は%s\n",return_list_decoy_rloc); memset(nexthop,0,sizeof(nexthop)); memset(eidrequest_i,0,100); inet_pton(AF_INET6, return_list_victim_eid, eidrequest_i); // printf("ipv6_start->af, flag, ttl == %d, %d, %d\n",ipv6_start.af, ipv6_start.flag, ipv6_start.ttl); prefix = match_dst_with_limit(&ipv6_start, eidrequest_i, nexthop, &reply_af, &ttl, request_prefix); printf("prefix == %d\n",prefix); if(prefix > 0){ syslog_write(LOG_INFO, "map-request: matched /%d map-cache", prefix); printf("ポジティブキャッシュ\n"); printf("IPv6 のカプセル作成(ヘッダー)\n"); 68 reply.h.REC_COUNT = 1; reply.h.E = 0; reply.h.P = 0; reply.h.TYPE = 2; memcpy(reply.h.NONCE, nonce, 8); size += sizeof(struct rep_header); if(request_af == 2){ clear_hostbit(AF_INET6, request_eid, prefix); if(reply_af == 2){//IPv6 の通信に使う部分 printf("IPv6 のカプセル作成(ペイロード)\n"); reply.d.d66.TTL = ttl; reply.d.d66.LOC_COUNT = 1; reply.d.d66.EID_MASKLEN = prefix; reply.d.d66.ACT = 0; reply.d.d66.A = 1; reply.d.d66.EID_AFI = request_af; memcpy(reply.d.d66.EID_PREFIX, request_eid, 16); horder(reply.d.d66.EID_PREFIX, 16); reply.d.d66.WEIGHT = 100; reply.d.d66.PRIORITY = 0; reply.d.d66.LOC_AFI = reply_af; reply.d.d66.R = 1; reply.d.d66.P = 0; reply.d.d66.L = 0; memset(nexthop,0,sizeof(nexthop)); memset(nexthop_i,0,100); inet_pton(AF_INET6, return_list_decoy_rloc, nexthop_i); memcpy(nexthop, nexthop_i, 16); // memcpy(nexthop,return_list_decoy_rloc,16);//nexthop を初期化して、局所化リストから受け取った囮 RLOC をセットする // printf("セットされた nexthop == %s\n",nexthop); memcpy(reply.d.d66.LOCATOR, nexthop, 16); // printf("セットされた reply.d.d66.LOCATOR == %s\n",reply.d.d66.LOCATOR); horder(reply.d.d66.LOCATOR, 16); size += sizeof(struct rep_data66); /* for syslog */ char log_eid_addr[100]; char log_rloc_addr[100]; inet_ntop(AF_INET6, request_eid, log_eid_addr, 100); inet_ntop(AF_INET6, nexthop, log_rloc_addr, 100); syslog_write(LOG_INFO, "map-reply: %s/%d -> %s ttl %d minutes", log_eid_addr, prefix, log_rloc_addr, ttl); printf("map-reply で送る内容: %s/%d -> %s ttl %d minutes\n", log_eid_addr, prefix, log_rloc_addr, ttl); memset(return_list_decoy_rloc,’\0’,100);//次回に備えて初期化しておく(これをしないとゴミが残ってしまう) memset(nexthop,0,sizeof(nexthop)); memset(nexthop_i,0,100); memset(reply.d.d66.LOCATOR,0,sizeof(reply.d.d66.LOCATOR)); }else if(reply_af == 1){ printf("IPv6 over IPv4 ペイロード作成\n"); reply.d.d64.TTL = ttl; reply.d.d64.LOC_COUNT = 1; reply.d.d64.EID_MASKLEN = prefix; reply.d.d64.ACT = 0; reply.d.d64.A = 1; reply.d.d64.EID_AFI = request_af; memcpy(reply.d.d64.EID_PREFIX, request_eid, 16); horder(reply.d.d64.EID_PREFIX, 16); reply.d.d64.WEIGHT = 100; reply.d.d64.PRIORITY = 0; reply.d.d64.LOC_AFI = reply_af; reply.d.d64.R = 1; reply.d.d64.P = 0; reply.d.d64.L = 0; memcpy(reply.d.d64.LOCATOR, nexthop, 4); horder(reply.d.d64.LOCATOR, 4); size += sizeof(struct rep_data64); /* for syslog */ 69 char log_eid_addr[100]; char log_rloc_addr[100]; inet_ntop(AF_INET6, request_eid, log_eid_addr, 100); inet_ntop(AF_INET, nexthop, log_rloc_addr, 100); syslog_write(LOG_INFO, "map-reply: %s/%d -> %s ttl %d minutes", log_eid_addr, prefix, log_rloc_addr, ttl); } }else if(request_af == 1){ clear_hostbit(AF_INET, request_eid, prefix); if(reply_af == 2){ printf("IPv4 over IPv6 ペイロード作成\n"); reply.d.d46.TTL = ttl; reply.d.d46.LOC_COUNT = 1; reply.d.d46.EID_MASKLEN = prefix; reply.d.d46.ACT = 0; reply.d.d46.A = 1; reply.d.d46.EID_AFI = request_af; memcpy(reply.d.d46.EID_PREFIX, request_eid, 4); horder(reply.d.d46.EID_PREFIX, 4); reply.d.d46.WEIGHT = 100; reply.d.d46.PRIORITY = 0; reply.d.d46.LOC_AFI = reply_af; reply.d.d46.R = 1; reply.d.d46.P = 0; reply.d.d46.L = 0; memcpy(reply.d.d46.LOCATOR, nexthop, 16); horder(reply.d.d46.LOCATOR, 16); size += sizeof(struct rep_data46); /* for syslog */ char log_eid_addr[100]; char log_rloc_addr[100]; inet_ntop(AF_INET, request_eid, log_eid_addr, 100); inet_ntop(AF_INET6, nexthop, log_rloc_addr, 100); syslog_write(LOG_INFO, "map-reply: %s/%d -> %s ttl %d minutes", log_eid_addr, prefix, log_rloc_addr, ttl); }else if(reply_af == 1){ printf("IPv4 ペイロード作成\n"); reply.d.d44.TTL = ttl; reply.d.d44.LOC_COUNT = 1; reply.d.d44.EID_MASKLEN = prefix; reply.d.d44.ACT = 0; reply.d.d44.A = 1; reply.d.d44.EID_AFI = request_af; memcpy(reply.d.d44.EID_PREFIX, request_eid, 4); horder(reply.d.d44.EID_PREFIX, 4); reply.d.d44.WEIGHT = 100; reply.d.d44.PRIORITY = 0; reply.d.d44.LOC_AFI = reply_af; reply.d.d44.R = 1; reply.d.d44.P = 0; reply.d.d44.L = 0; memcpy(reply.d.d44.LOCATOR, nexthop, 4); horder(reply.d.d44.LOCATOR, 4); size += sizeof(struct rep_data44); /* for syslog */ char log_eid_addr[100]; char log_rloc_addr[100]; inet_ntop(AF_INET, request_eid, log_eid_addr, 100); inet_ntop(AF_INET, nexthop, log_rloc_addr, 100); syslog_write(LOG_INFO, "map-reply: %s/%d -> %s ttl %d minutes", log_eid_addr, prefix, log_rloc_addr, ttl); } } norder(&reply, size); send_reply_packet((char *)&reply, size); }else if(prefix < 0){ printf("ネガティブキャッシュ\n"); syslog_write(LOG_INFO, "map-request: matched /%d negative map-cache", prefix * -1); reply.h.REC_COUNT = 1; 70 reply.h.E = 0; reply.h.P = 0; reply.h.TYPE = 2; memcpy(reply.h.NONCE, nonce, 8); size += sizeof(struct rep_header); if(request_af == 2){ printf("パケット作成(ネガティブキャッシュ,request_af == 2)\n"); clear_hostbit(AF_INET6, request_eid, prefix * -1); reply.d.d60.TTL = 15; reply.d.d60.LOC_COUNT = 0; reply.d.d60.EID_MASKLEN = prefix * -1; reply.d.d60.ACT = 1; reply.d.d60.A = 1; reply.d.d60.EID_AFI = request_af; memcpy(reply.d.d60.EID_PREFIX, request_eid, 16); horder(reply.d.d60.EID_PREFIX, 16); size += sizeof(struct rep_data60); /* for syslog */ char log_eid_addr[100]; inet_ntop(AF_INET6, request_eid, log_eid_addr, 100); syslog_write(LOG_INFO, "map-reply: %s/%d -> NativelyForward ttl %d minutes", log_eid_addr, prefix * -1, 15); }else if(request_af == 1){ printf("パケット作成(ネガティブキャッシュ,request_af == 1)\n"); clear_hostbit(AF_INET, request_eid, prefix * -1); reply.d.d40.TTL = 15; reply.d.d40.LOC_COUNT = 0; reply.d.d40.EID_MASKLEN = prefix * -1; reply.d.d40.ACT = 1; reply.d.d40.A = 1; reply.d.d40.EID_AFI = request_af; memcpy(reply.d.d40.EID_PREFIX, request_eid, 4); horder(reply.d.d40.EID_PREFIX, 4); size += sizeof(struct rep_data40); /* for syslog */ char log_eid_addr[100]; inet_ntop(AF_INET, request_eid, log_eid_addr, 100); syslog_write(LOG_INFO, "map-reply: %s/%d -> NativelyForward ttl %d minutes", log_eid_addr, prefix * -1, 15); } norder(&reply, size); send_reply_packet((char *)&reply, size); } } //ここまで提案部分 if(list_check == 0){ printf("クライアントはアタッカーじゃない\n"); if(prefix > 0){ syslog_write(LOG_INFO, "map-request: matched /%d map-cache", prefix); printf("IPv6 のカプセル作成(ヘッダー)\n"); reply.h.REC_COUNT = 1; reply.h.E = 0; reply.h.P = 0; reply.h.TYPE = 2; memcpy(reply.h.NONCE, nonce, 8); size += sizeof(struct rep_header); if(request_af == 2){ clear_hostbit(AF_INET6, request_eid, prefix); if(reply_af == 2){ printf("IPv6 のカプセル作成(ペイロード)\n"); reply.d.d66.TTL = ttl; 71 reply.d.d66.LOC_COUNT = 1; reply.d.d66.EID_MASKLEN = prefix; reply.d.d66.ACT = 0; reply.d.d66.A = 1; reply.d.d66.EID_AFI = request_af; memcpy(reply.d.d66.EID_PREFIX, request_eid, 16); horder(reply.d.d66.EID_PREFIX, 16); reply.d.d66.WEIGHT = 100; reply.d.d66.PRIORITY = 0; reply.d.d66.LOC_AFI = reply_af; reply.d.d66.R = 1; reply.d.d66.P = 0; reply.d.d66.L = 0; memcpy(reply.d.d66.LOCATOR, nexthop, 16); // // // inet_ntop(AF_INET, nexthop, nexthop_i, 100); printf("nexthop == %s\n",nexthop_i); printf("reply.d.d66.LOCATOR == %s\n",reply.d.d66.LOCATOR); horder(reply.d.d66.LOCATOR, 16); // // // inet_ntop(AF_INET, nexthop, nexthop_i, 100); printf("nexthop == %s\n",nexthop_i); printf("reply.d.d66.LOCATOR == %s\n",reply.d.d66.LOCATOR); size += sizeof(struct rep_data66); // // // inet_ntop(AF_INET, nexthop, nexthop_i, 100); printf("nexthop == %s\n",nexthop_i); printf("reply.d.d66.LOCATOR == %s\n",reply.d.d66.LOCATOR); /* for syslog */ char log_eid_addr[100]; char log_rloc_addr[100]; // printf("log_rloc_addr == %s\n",log_rloc_addr); inet_ntop(AF_INET6, request_eid, log_eid_addr, 100); inet_ntop(AF_INET6, nexthop, log_rloc_addr, 100); // printf("nexthop == %s\n",nexthop); // printf("log_rloc_addr == %s\n",log_rloc_addr); syslog_write(LOG_INFO, "map-reply: %s/%d -> %s ttl %d minutes", log_eid_addr, prefix, log_rloc_addr, ttl); printf("map-reply で送る内容: %s/%d -> %s ttl %d minutes\n", log_eid_addr, prefix, log_rloc_addr, ttl); }else if(reply_af == 1){ printf("IPv6 over IPv4 ペイロード作成\n"); reply.d.d64.TTL = ttl; reply.d.d64.LOC_COUNT = 1; reply.d.d64.EID_MASKLEN = prefix; reply.d.d64.ACT = 0; reply.d.d64.A = 1; reply.d.d64.EID_AFI = request_af; memcpy(reply.d.d64.EID_PREFIX, request_eid, 16); horder(reply.d.d64.EID_PREFIX, 16); reply.d.d64.WEIGHT = 100; reply.d.d64.PRIORITY = 0; reply.d.d64.LOC_AFI = reply_af; reply.d.d64.R = 1; reply.d.d64.P = 0; reply.d.d64.L = 0; memcpy(reply.d.d64.LOCATOR, nexthop, 4); horder(reply.d.d64.LOCATOR, 4); size += sizeof(struct rep_data64); /* for syslog */ char log_eid_addr[100]; char log_rloc_addr[100]; inet_ntop(AF_INET6, request_eid, log_eid_addr, 100); inet_ntop(AF_INET, nexthop, log_rloc_addr, 100); syslog_write(LOG_INFO, "map-reply: %s/%d -> %s ttl %d minutes", log_eid_addr, prefix, log_rloc_addr, ttl); } }else if(request_af == 1){ 72 clear_hostbit(AF_INET, request_eid, prefix); if(reply_af == 2){ printf("IPv4 over IPv6 ペイロード作成\n"); reply.d.d46.TTL = ttl; reply.d.d46.LOC_COUNT = 1; reply.d.d46.EID_MASKLEN = prefix; reply.d.d46.ACT = 0; reply.d.d46.A = 1; reply.d.d46.EID_AFI = request_af; memcpy(reply.d.d46.EID_PREFIX, request_eid, 4); horder(reply.d.d46.EID_PREFIX, 4); reply.d.d46.WEIGHT = 100; reply.d.d46.PRIORITY = 0; reply.d.d46.LOC_AFI = reply_af; reply.d.d46.R = 1; reply.d.d46.P = 0; reply.d.d46.L = 0; memcpy(reply.d.d46.LOCATOR, nexthop, 16); horder(reply.d.d46.LOCATOR, 16); size += sizeof(struct rep_data46); /* for syslog */ char log_eid_addr[100]; char log_rloc_addr[100]; inet_ntop(AF_INET, request_eid, log_eid_addr, 100); inet_ntop(AF_INET6, nexthop, log_rloc_addr, 100); syslog_write(LOG_INFO, "map-reply: %s/%d -> %s ttl %d minutes", log_eid_addr, prefix, log_rloc_addr, ttl); }else if(reply_af == 1){ printf("IPv4 ペイロード作成\n"); reply.d.d44.TTL = ttl; reply.d.d44.LOC_COUNT = 1; reply.d.d44.EID_MASKLEN = prefix; reply.d.d44.ACT = 0; reply.d.d44.A = 1; reply.d.d44.EID_AFI = request_af; memcpy(reply.d.d44.EID_PREFIX, request_eid, 4); horder(reply.d.d44.EID_PREFIX, 4); reply.d.d44.WEIGHT = 100; reply.d.d44.PRIORITY = 0; reply.d.d44.LOC_AFI = reply_af; reply.d.d44.R = 1; reply.d.d44.P = 0; reply.d.d44.L = 0; memcpy(reply.d.d44.LOCATOR, nexthop, 4); horder(reply.d.d44.LOCATOR, 4); size += sizeof(struct rep_data44); /* for syslog */ char log_eid_addr[100]; char log_rloc_addr[100]; inet_ntop(AF_INET, request_eid, log_eid_addr, 100); inet_ntop(AF_INET, nexthop, log_rloc_addr, 100); syslog_write(LOG_INFO, "map-reply: %s/%d -> %s ttl %d minutes", log_eid_addr, prefix, log_rloc_addr, ttl); } } norder(&reply, size); send_reply_packet((char *)&reply, size); }else if(prefix < 0){ syslog_write(LOG_INFO, "map-request: matched /%d negative map-cache", prefix * -1); printf("ネガティブキャッシュ\n"); reply.h.REC_COUNT = 1; reply.h.E = 0; reply.h.P = 0; reply.h.TYPE = 2; memcpy(reply.h.NONCE, nonce, 8); size += sizeof(struct rep_header); if(request_af == 2){ 73 printf("パケット作成(ネガティブキャッシュ,request_af == 2)\n"); clear_hostbit(AF_INET6, request_eid, prefix * -1); reply.d.d60.TTL = 15; reply.d.d60.LOC_COUNT = 0; reply.d.d60.EID_MASKLEN = prefix * -1; reply.d.d60.ACT = 1; reply.d.d60.A = 1; reply.d.d60.EID_AFI = request_af; memcpy(reply.d.d60.EID_PREFIX, request_eid, 16); horder(reply.d.d60.EID_PREFIX, 16); size += sizeof(struct rep_data60); /* for syslog */ char log_eid_addr[100]; inet_ntop(AF_INET6, request_eid, log_eid_addr, 100); syslog_write(LOG_INFO, "map-reply: %s/%d -> NativelyForward ttl %d minutes", log_eid_addr, prefix * -1, 15); }else if(request_af == 1){ printf("パケット作成(ネガティブキャッシュ,request_af == 1)\n"); clear_hostbit(AF_INET, request_eid, prefix * -1); reply.d.d40.TTL = 15; reply.d.d40.LOC_COUNT = 0; reply.d.d40.EID_MASKLEN = prefix * -1; reply.d.d40.ACT = 1; reply.d.d40.A = 1; reply.d.d40.EID_AFI = request_af; memcpy(reply.d.d40.EID_PREFIX, request_eid, 4); horder(reply.d.d40.EID_PREFIX, 4); size += sizeof(struct rep_data40); /* for syslog */ char log_eid_addr[100]; inet_ntop(AF_INET, request_eid, log_eid_addr, 100); syslog_write(LOG_INFO, "map-reply: %s/%d -> NativelyForward ttl %d minutes", log_eid_addr, prefix * -1, 15); } norder(&reply, size); send_reply_packet((char *)&reply, size); }else{ syslog_write(LOG_INFO, "map-request: not matched any map-cache"); printf("map-request: not matched any map-cache(全然関係ないリクエストだった)\n"); } } } void parse_request_header(char *buf, int readsize){ /* NOT SUPPORTED IPv4 in IPv6 and IPv6 in IPv4 */ /* NOT SUPPORTED MULTIPLE REQUEST */ int size = readsize; char result_eid[16]; int result_prefix; int result_af; struct req_header *h = (struct req_header *)buf; memset(result_eid, 0, 16); if(h->TYPE == 1){ int irc = h->IRC; char *ptr = buf + 12; // char *ptr; // ptr = NULL; // ptr = (char *)malloc(sizeof(buf + 12)); // memset(ptr, 0, sizeof(buf + 12)); // ptr = buf + 12; size = readsize - 12; // parse_request_data(result_eid, &result_prefix, &result_af, ptr, size, irc); // int check_v4 = 0; 74 check_v4 = parse_request_data(result_eid, &result_prefix, &result_af, ptr, size, irc); // free(ptr); // if(check_v4 == 0){ create_reply_packet(result_eid, result_prefix, result_af, h->NONCE); memset(result_eid, 0, 16); // free(ptr); // } } } //void parse_request_data(char *result_eid, int *result_prefix, int *result_af, char *buf, int size, int irc){ int parse_request_data(char *result_eid, int *result_prefix, int *result_af, char *buf, int size, int irc){ uint8_t *num; char *ptr = buf; int recsize = size; int i; int s; struct req_data6 *req6; struct req_data4 *req4; norder(buf, size); for(i = 0; i < irc + 2; i++){ num = (uint8_t *)ptr; if(num[1] == 2){ ptr = ptr + 18; recsize -= 18; }else if(num[1] == 1){ ptr = ptr + 6; recsize -= 6; }else if(num[1] == 0){ ptr = ptr + 2; recsize -= 2; }else{ warn("map-request parse error"); } } horder(ptr, recsize); req6 = (struct req_data6 *)ptr; if(req6->D_EID_AFI == 2){ norder(req6->D_EID, 16); memcpy(result_eid, req6->D_EID, 16); *result_prefix = req6->D_EID_MASKLEN; *result_af = 2; /* for syslog */ char log_eid_addr[100]; inet_ntop(AF_INET6, result_eid, log_eid_addr, 100); syslog_write(LOG_INFO, "map-request: %s/%d ?", log_eid_addr, *result_prefix); printf("map-request6: %s/%d \n", log_eid_addr, *result_prefix); return 0; }else if(req6->D_EID_AFI == 1){ req4 = (struct req_data4 *)req6; norder(req4->D_EID, 4); memcpy(result_eid, req4->D_EID, 4); *result_prefix = req4->D_EID_MASKLEN; *result_af = 1; /* for syslog */ char log_eid_addr[100]; inet_ntop(AF_INET, result_eid, log_eid_addr, 100); syslog_write(LOG_INFO, "map-request: %s/%d ?", log_eid_addr, *result_prefix); printf("map-request4: %s/%d (v4 は破棄)\n", log_eid_addr, *result_prefix); return 1; } } 75