バットフィッシュ はじめに

画像



最新のネットワークの問題の1つは、その脆弱性です。 多くのフィルタリングルール、ルーティング情報交換ポリシー、動的ルーティングプロトコルにより、ネットワークが混乱し、人的要因の影響を受けやすくなります。 ルートマップまたはACL( onetwo )を変更すると、ネットワーククラッシュが意図せずに発生する可能性があります。 実稼働環境に変更を加える前に、新しい構成を使用してネットワークの動作を評価するツールは間違いなく不足しています。 プロバイダーBから受信したBGPアナウンスメントの一部を除外すると、ネットワークAが利用可能になるかどうかを確実に知りたいですか? トランジットリンクの1つでIGPメトリックを2倍にした場合、パケットはネットワークCからサーバーDにどのようなルートで行きますか? Batfishは、これらおよび他の多くの質問に答えるのに役立ちます!



バットフィッシュの口コミ



Batfishはネットワークモデリングツールです。 その主な目的は、実稼働ネットワークに反映する前に構成の変更をテストすることです。 Batfishを使用して、ネットワークの現在のステータスを分析および確認することもできます。 ネットワークの世界の既存のCI / CDプロセスには、新しい構成をテストするためのツールが明らかに欠けています。 Batfishはこの問題を解決します。



Batfishは、既存のネットワーク機器に直接直接アクセスする必要はありません。Batfishは、デバイス構成ファイルに含まれるデータに基づいてネットワークの動作をモデル化します。



バットフィッシュができること:







サポートされているプラ​​ットフォーム:





画像



BatfishはJavaアプリケーションです。 便利な作業のために、Pybatfish-python SDKが作成されました。



練習に移りましょう。 例でBatfishの可能性を示します。





AS 41214とAS 10631の2つの自律システムを管理します。IGPとして、AS-41214はIS-ISとAS-10631-OSPFを使用します。 各AS内では、IBGP-fullmeshが使用されます。 LDN-CORE-01は、BGPネイバープレフィックス135.65.0.0/19、MSK-CORE-01-140.0.0.0/24を発表します。 自律システム間のルーティング情報の交換は、HKI-CORE-01-SPB-CORE-01のジャンクションで発生します。



HKI-CORE-01、STH-CORE-01 -Junosルーター

LDN-CORE-01、AMS-CORE-01、SPB-CORE-01、MSK-CORE-01 -Cisco IOSルーター







BatfishとPython SDKを使用してコンテナーをインストールします。



docker pull batfish/allinone docker run batfish/allinone docker container exec -it <container> bash
      
      





Pythonインタラクティブモードでライブラリを知る:



 root@ea9a1559d88e:/# python3 -------------------- >>> from pybatfish.client.commands import bf_logger, bf_init_snapshot >>> from pybatfish.question.question import load_questions >>> from pybatfish.question import bfq >>> import logging >>> bf_logger.setLevel(logging.ERROR) >>> load_questions() >>> bf_init_snapshot('tmp/habr') 'ss_e8065858-a911-4f8a-b020-49c9b96d0381'
      
      





bf_init_snapshot( 'tmp / habr') -この機能は、構成ファイルをBatfishにロードし、分析のためにそれらを準備します。



/ tmp / habr-ルーター構成ファイルのあるディレクトリ。



 root@ea9a1559d88e:/tmp/habr# tree . `-- configs |-- AMS-CORE-01.cfg |-- HKI-CORE-01.cfg |-- LDN-CORE-01.cfg |-- MSK-CORE-01.cfg |-- SPB-CORE-01.cfg `-- STH-CORE-01.cfg 1 directory, 6 files
      
      





次に、LDN-CORE-01ルーターのBGPセッションのステータスを確認します。



 >>> bgp_peers = bfq.bgpSessionStatus(nodes='LDN-CORE-01').answer().frame() >>> bgp_peers Node VRF Local_AS Local_IP Remote_AS Remote_Node Remote_IP Session_Type Est_Status 0 ldn-core-01 default 41214 172.20.20.1 41214 sth-core-01 172.20.20.2 IBGP EST 1 ldn-core-01 default 41214 172.20.20.1 41214 ams-core-01 172.20.20.3 IBGP EST 2 ldn-core-01 default 41214 172.20.20.1 41214 hki-core-01 172.20.20.4 IBGP EST
      
      





まあどう? 真実のように聞こえますか?



 LDN-CORE-01#show ip bgp summary … Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd 172.20.20.2 4 41214 629 669 9 0 0 00:56:51 0 172.20.20.3 4 41214 826 827 9 0 0 01:10:18 0 172.20.20.4 4 41214 547 583 9 0 0 00:49:24 1
      
      





次に、BatfishによるHKI-CORE-01ルーターのRIBにあるIS-ISルートを見てみましょう。



 >>> isis_routes = bfq.routes(nodes='HKI-CORE-01', protocols='isis').answer().frame() >>> isis_routes Node VRF Network Next_Hop Next_Hop_IP Protocol Admin_Distance Metric Tag 0 hki-core-01 default 172.20.20.3/32 ams-core-01 10.0.0.6 isisL2 18 20 None 1 hki-core-01 default 172.20.20.1/32 ams-core-01 10.0.0.6 isisL2 18 30 None 2 hki-core-01 default 172.20.20.2/32 sth-core-01 10.0.0.4 isisL2 18 10 None 3 hki-core-01 default 172.20.20.1/32 sth-core-01 10.0.0.4 isisL2 18 30 None 4 hki-core-01 default 10.0.0.0/31 sth-core-01 10.0.0.4 isisL2 18 20 None 5 hki-core-01 default 10.0.0.2/31 ams-core-01 10.0.0.6 isisL2 18 20 None
      
      





コマンドラインで:



 showroute@HKI-CORE-01# run show route table inet.0 protocol isis inet.0: 18 destinations, 18 routes (18 active, 0 holddown, 0 hidden) + = Active Route, - = Last Active, * = Both 10.0.0.0/31 *[IS-IS/18] 00:51:25, metric 20 > to 10.0.0.4 via ge-0/0/0.0 10.0.0.2/31 *[IS-IS/18] 00:51:45, metric 20 > to 10.0.0.6 via ge-0/0/1.0 172.20.20.1/32 *[IS-IS/18] 00:51:25, metric 30 to 10.0.0.4 via ge-0/0/0.0 > to 10.0.0.6 via ge-0/0/1.0 172.20.20.2/32 *[IS-IS/18] 00:51:25, metric 10 > to 10.0.0.4 via ge-0/0/0.0 172.20.20.3/32 *[IS-IS/18] 00:51:45, metric 20 > to 10.0.0.6 via ge-0/0/1.0
      
      





いいね! バットフィッシュがあることがあなたに明らかになったと思います。



記事の冒頭で、Batfishを使用して構成の変更を確認してから、「戦闘」ネットワークに接続できることを書きました。 次に、 RobotFrameworkに基づいたネットワークテストのプロセスを検討することを提案します。 これを行うために、PyBatfishに基づいて次のチェックを実行できる小さなモジュールを作成しました。





LibraryBatfish.py
 import logging from pybatfish.client.commands import bf_logger, bf_init_snapshot from pybatfish.question.question import load_questions, list_questions from pybatfish.question import bfq from pybatfish.datamodel.flow import HeaderConstraints, PathConstraints from robot.api import logger class LibraryBatfish(object): def __init__(self, snapshot): bf_logger.setLevel(logging.ERROR) load_questions() bf_init_snapshot(snapshot) def check_bgp_peers(self): not_established_peers = list() bgp_peers = bfq.bgpSessionStatus().answer() for peer in bgp_peers.rows: if peer.get('Established_Status') != 'ESTABLISHED': not_established_peers.append(dict.fromkeys(peer.get('Local_IP').split(), peer.get('Remote_IP').get('value'))) if len(not_established_peers) == 0: return 1 else: logger.warn('BGP neighbors are not in an established state:') for neighborship in not_established_peers: for peer in neighborship: logger.warn('{} - {}'.format(peer, neighborship.get(peer))) return 0 def check_routes(self, node, protocol): routes = bfq.routes(nodes=node, protocols=protocol).answer() return len(routes.rows) def check_isis_neighbors(self, description): not_isis_enabled_links = list() for link in self._get_isis_enabled_links(description): if link not in self._get_isis_neighbors(): not_isis_enabled_links.append(link) if len(not_isis_enabled_links) == 0: return 1 else: for link in not_isis_enabled_links: logger.warn('{} {} has no IS-IS neighbor'.format(link.get('hostname'), link.get('interface'))) return 0 def ping(self, source_ip, destination_ip): ip_owners = bfq.ipOwners().answer() traceroute = self._get_traceroute_status(source_ip, destination_ip, ip_owners) reverse_traceroute = self._get_traceroute_status(destination_ip, source_ip, ip_owners) if traceroute == True and reverse_traceroute == True: self._show_trace(source_ip, destination_ip, ip_owners) return 1 else: logger.warn('Ping {} -> {} failed'.format(source_ip, destination_ip)) return 0 def _get_traceroute_status(self, source_ip, destination_ip, addresses): tracert = self._unidirectional_virtual_traceroute(source_ip, destination_ip, addresses) isAccepted = True if tracert != None: for trace in tracert.rows[0].get('Traces'): if trace.get('disposition') != 'ACCEPTED': isAccepted = False if isAccepted == True: return True else: return False def _get_paths(self, source_ip, destination_ip, addresses): tracert = self._unidirectional_virtual_traceroute(source_ip, destination_ip, addresses) traces = tracert.rows[0].get('Traces') paths = dict() path_number = 1 for trace in traces: if trace.get('disposition') == 'ACCEPTED': path = list() for hop in trace.get('hops'): path.append(hop.get('node').get('name')) paths[path_number] = path path_number += 1 return paths def _unidirectional_virtual_traceroute(self, source_ip, destination_ip, addresses): for address in addresses.rows: if address.get('IP') == source_ip: node = address.get('Node').get('name') int = address.get('Interface') headers = HeaderConstraints(srcIps=source_ip, dstIps=destination_ip, ipProtocols=['ICMP']) try: tracert = bfq.traceroute(startLocation="{}[{}]".format(node,int), headers=headers).answer() return tracert except: logger.warn('{} address has not been found'.format(source_ip)) def _get_isis_enabled_links(self, description='core-link'): isis_enabled_links = list() interfaces = bfq.interfaceProperties().answer() for int in interfaces.rows: if int.get('Description') != None and description in int.get('Description'): isis_enabled_links.append({'hostname' : int.get('Interface').get('hostname'), 'interface' : int.get('Interface').get('interface')}) return isis_enabled_links def _get_isis_neighbors(self): isis_neighbors = list() isis_adjacencies = bfq.edges(edgeType='isis').answer() for neighbor in isis_adjacencies.rows: isis_neighbors.append(neighbor.get('Interface')) return isis_neighbors def _show_trace(self, source_ip, destination_ip, addresses): logger.console('\nTraceroute to {} from {}'.format(destination_ip, source_ip)) paths = self._get_paths(source_ip, destination_ip, addresses) path_num = 1 for path in paths: n = 1 logger.console('\n Path N{}'.format(path_num)) for hop in paths.get(path): logger.console(' {} {}'.format(n, hop)) n += 1 path_num += 1
      
      







batfish-test.robot
画像



シナリオN1







私の管理下では、まだ同じネットワークです。 AS 41214AS 10631の境界にあるフィルターをクリーンアップし、BOGONS範囲のソースまたは宛先IPアドレスを含むジャンクションパケットでブロックする必要があるとします。



変更を行う前にテストを実行します。



画像



テストに合格しました。



HKI-CORE-01ルーターのテスト構成-/tmp/habr/configs/ HKI-CORE- 01.cfgを変更します。



 set firewall family inet filter BOGONS term TERM010 from address 0.0.0.0/8 set firewall family inet filter BOGONS term TERM010 from address 10.0.0.0/8 set firewall family inet filter BOGONS term TERM010 from address 100.64.0.0/10 set firewall family inet filter BOGONS term TERM010 from address 127.0.0.0/8 set firewall family inet filter BOGONS term TERM010 from address 169.254.0.0/16 set firewall family inet filter BOGONS term TERM010 from address 172.16.0.0/12 set firewall family inet filter BOGONS term TERM010 from address 192.0.2.0/24 set firewall family inet filter BOGONS term TERM010 from address 192.88.99.0/24 set firewall family inet filter BOGONS term TERM010 from address 192.168.0.0/16 set firewall family inet filter BOGONS term TERM010 from address 198.18.0.0/15 set firewall family inet filter BOGONS term TERM010 from address 198.51.100.0/24 set firewall family inet filter BOGONS term TERM010 from address 203.0.113.0/24 set firewall family inet filter BOGONS term TERM010 from address 224.0.0.0/4 set firewall family inet filter BOGONS term TERM010 from address 240.0.0.0/4 set firewall family inet filter BOGONS term TERM010 then discard set firewall family inet filter BOGONS term PERMIT-IP-ANY-ANY then accept set interfaces ge-0/0/2.0 family inet filter input BOGONS set interfaces ge-0/0/2.0 family inet filter output BOGONS
      
      





テストを実行します。







私は非常に近かったが、テスト出力が示すように、BGPの変更が行われた後、近隣192.168.30.0-192.168.30.1は確立状態ではない->結果として、ポイント135.65.0.1 <-> 140.0.0.1間のIP接続が失われます。 何が悪いの? HKI-CORE-01構成を注意深く見て、eBGPピアリングがプライベートアドレスにインストールされていることを確認します。



 showroute@HKI-CORE-01# show interfaces ge-0/0/2 | display set set interfaces ge-0/0/2 description SPB-CORE-01 set interfaces ge-0/0/2 unit 0 family inet filter input BOGONS set interfaces ge-0/0/2 unit 0 family inet filter output BOGONS set interfaces ge-0/0/2 unit 0 family inet address 192.168.30.0/31
      
      





結論:ジャンクションでアドレスを変更するか、192.168.30.0 / 31サブネットを例外に追加する必要があります。



ジャンクションのネットワークを例外に追加し、/ tmp / habr / configs / HKI-CORE-01.cfgを再度更新します。



 set firewall family inet filter BOGONS term TERM005 from address 192.168.0.0/31 set firewall family inet filter BOGONS term TERM005 then accept
      
      





テストを実行します。







これで、不要なトラフィックはebgpインターフェイスAS 41214-AS 10631を通過しなくなります。結果を恐れることなく安全に変更を加えることができます。



シナリオN2







ここで、 MSK-CORE-01ルーターでネットワーク150.0.0.0/24を終了し、ポイント135.65.0.1と150.0.0.1間の接続を確認する必要があります



次の行をMSK-CORE-01ルーターのテスト構成に追加します-tmp / habr / configs / MSK-CORE-01.cfg:



 interface Loopback2 ip address 150.0.0.1 255.255.255.255 ! ip route 150.0.0.0 255.255.255.0 Null0 ! router bgp 10631 ! address-family ipv4 network 150.0.0.0 mask 255.255.255.0 !
      
      





テストスクリプトを変更して、テストを実行します。



 git diff HEAD~ diff --git a/batfish-robot.robot b/batfish-robot.robot index 8d963c5..ce8cb6a 100644 --- a/batfish-robot.robot +++ b/batfish-robot.robot @@ -5,7 +5,7 @@ Library LibraryBatfish.py tmp/habr ${ISIS-ENABLED-LINK-DESCRIPTION} ISIS-LINK ${NODE} HKI-CORE-01 ${PROTOCOL} ebgp -${RIB-SIZE} 1 +${RIB-SIZE} 2 *** Test Cases *** ISIS @@ -27,3 +27,8 @@ Ping [Documentation] Test end-to-end ICMP connectivity & show traceroute ${result}= Ping 135.65.0.1 140.0.0.1 Should Be Equal As Integers ${result} 1 + +Ping2 + [Documentation] Test end-to-end ICMP connectivity & show traceroute + ${result}= Ping 135.65.0.1 150.0.0.1 + Should Be Equal As Integers ${result} 1
      
      





これで、HKI-CORE-01ルーターに2つのeBGPルートが表示されると予想されるため、追加の接続チェックが追加されます







135.65.0.1と150.0.0.1の間には接続がありません。さらに、 HKI-CORE-01ルーターには 、eBGPルートが2つでなく1つしかありません。



新しい構成をMSK-CORE-01ルーターに追加するときは、 HKI-CORE-01のRIBの内容を確認します。



 showroute@HKI-CORE-01# run show route table inet.0 protocol bgp inet.0: 20 destinations, 20 routes (19 active, 0 holddown, 1 hidden) + = Active Route, - = Last Active, * = Both 135.65.0.0/19 *[BGP/170] 02:25:38, MED 0, localpref 100, from 172.20.20.1 AS path: I, validation-state: unverified > to 10.0.0.4 via ge-0/0/0.0 to 10.0.0.6 via ge-0/0/1.0 140.0.0.0/24 *[BGP/170] 01:38:02, localpref 100 AS path: 10631 I, validation-state: unverified > to 192.168.30.1 via ge-0/0/2.0 showroute@HKI-CORE-01# run show route table inet.0 protocol bgp hidden detail inet.0: 20 destinations, 20 routes (19 active, 0 holddown, 1 hidden) 150.0.0.0/24 (1 entry, 0 announced) BGP /-101 Next hop type: Router, Next hop index: 563 Address: 0x940f43c Next-hop reference count: 4 Source: 192.168.30.1 Next hop: 192.168.30.1 via ge-0/0/2.0, selected Session Id: 0x9 State: <Hidden Ext> Local AS: 41214 Peer AS: 10631 Age: 1:42:03 Validation State: unverified Task: BGP_10631.192.168.30.1+179 AS path: 10631 I Localpref: 100 Router ID: 10.68.1.1 Hidden reason: rejected by import policy
      
      





SPB-CORE-01から受信したプレフィックスのインポートポリシーに注意してください。



 set protocols bgp group AS10631 import FROM-AS10631 set protocols bgp group AS10631 neighbor 192.168.30.1 description SPB-CORE-01 set protocols bgp group AS10631 neighbor 192.168.30.1 peer-as 10631 set policy-options policy-statement FROM-AS10631 term TERM010 from route-filter 140.0.0.0/24 exact set policy-options policy-statement FROM-AS10631 term TERM010 then accept set policy-options policy-statement FROM-AS10631 term DENY then reject
      
      





150.0.0.0/24を許可するルールがありません。 テスト構成に追加して、テストを実行します。



 showroute@HKI-CORE-01# show | compare [edit policy-options policy-statement FROM-AS10631 term TERM010 from] route-filter 140.0.0.0/24 exact { ... } + route-filter 150.0.0.0/24 exact; [edit]
      
      









ネットワーク間に接続性があり、すべてのテストに合格しました! したがって、「戦闘」ネットワークの作業にこれらの変更を加えることができます。



おわりに



私の意見では、Batfishは大きな可能性を秘めた強力なツールです。 試してみて、自分の目で確かめてください。



このトピックがおもしろい場合は、スラックチャットに参加してください。Batfish開発者は質問に答えてバグをすばやく修正できます。



batfish-org.slack.com



ご清聴ありがとうございました。



参照資料



www.batfish.org



www.youtube.com/channel/UCA-OUW_3IOt9U_s60KvmJYA



github.com/batfish/batfish



media.readthedocs.org/pdf/pybatfish/latest/pybatfish.pdf



github.com/showroute/batfish-habr



All Articles