Batfishの手引き（ACLの解析）

# はじめに
前の記事でセットアップしたBatfishを活用します。
今回はACLの分析、トレースルート、config差分の確認を実施します。

前の記事

https://qiita.com/Trick_Trick/items/b57ddb2f9394bfed94e0

# 1.ACLの分析
ACLを読み込み
①無意味なフィルターのチェック
②特定IPからの通信の許可/拒否のチェック
③特定サブネットからの通信の許可/拒否のチェック
を行います。

## 1.0 前提作業
後に紹介する①～③の解析実施の前に、
configの読み込みなどのセットアップを行います。

### コード
```python
# ここのパスを自分が格納したフォルダパスに変更する
SNAPSHOT_PATH = "networks/example-filters/current"

# 後は手を付けない
%run startup.py
bf = Session(host="localhost")
bf.set_network("network-example-filters")
SNAPSHOT_NAME = "current"
bf.init_snapshot(SNAPSHOT_PATH, name=SNAPSHOT_NAME, overwrite=True)
```

## 1.1 無意味フィルターのチェック
ここから本題になります。

```python
10 deny 192.168.100.0/24
20 permit 192.168.100.254/32 
30 permit any
```
この20番のような意味の無いフィルターをチェックします。

### コード
```python
# Find unreachable lines in filters of rtr-with-acl
aclAns = bf.q.filterLineReachability(nodes="rtr-with-acl").answer()
show(aclAns.frame().sort_values(by="Unreachable_Line"))
```
### 結果の見方
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507183/0edbf700-1d77-c209-8e4d-733d14968331.png)

670行目が540行目によって意味の無い行
790行目が500行目によって意味の無い行
となっていることが分かります。

670行目はDifferent_Action欄がTrueとなっていますが、
これは670行目で意図したpermitが、540行目のdenyで否定されていることを示しており、
より深刻なミスであることを表します。


## 1.2 特定IPからの疎通の確認

特定の送信元から特定の送信先への通信が許可されるかを解析します。


### コード
```python
flow_name = HeaderConstraints(srcIps="10.10.10.1",#送信元アドレス
                             dstIps="218.8.104.58",#宛先アドレス
                             applications=["dns"])#アプリケーション
answer = bf.q.testFilters(headers=flow_name,
                         nodes="rtr-with-acl",#解析するACLを持つ機器のホスト名
                         filters="acl_in").answer()#解析するACLの名前
show(answer.frame())
```

### 結果の見方

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507183/8c1bdc2b-9a46-45a0-702c-bc1546cd8d57.png)

表のAction欄にPermit or Denyが表示
Line_Content欄にPermit Denyの決め手になった行が表示。

## 1.3 特定サブネットからの疎通の確認

### できること
特定のサブネットから特定の送信先への通信が許可されるかを解析します。
### コード
```python
traffic_name = HeaderConstraints(srcIps="10.10.10.0/24",#送信元サブネットを記入
                                dstIps="218.8.104.58",#宛先IPを記入
                                applications=["dns"])#アプリケーションを指定
answer = bf.q.searchFilters(headers=traffic_name,
                           action="deny", #"deny"or"permit"を記入
                           filters="acl_in").answer()
show(answer.frame())
```
### 結果の見方
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507183/9db82d8a-f63f-32b6-6da5-47bf3b0bc9a5.png)

Action(deny, permit)に指定した内容に合致する条件があれば、
Line_content、Trace欄に表示される。

上記の場合、460行目に10.0.0.42/32を対象にdenyがあることが分かる。

# 2.トレースルートの実施
格納したconfigからトレースルートを実施します。
## 2.0 下準備＆configの指定
格納したconfigのパスをSNAPSHOT_PATHで指定。
今回はデフォルトで指定されているconfigを使用。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507183/40bfbfd3-6d59-5300-5fd7-effdfdcb1daf.png)


### コード
```python
SNAPSHOT_PATH = "networks/example" #config格納のパスを指定

# Import packages
%run startup.py
bf = Session(host="localhost")

NETWORK_NAME = "example_network"
SNAPSHOT_NAME = "example_snapshot"

bf.set_network(NETWORK_NAME)
bf.init_snapshot(SNAPSHOT_PATH, name=SNAPSHOT_NAME, overwrite=True)
```

## 2.1 トレースルートの実施 
ここから本題です。トレースルートを実施します。
### コード
```python
# start the traceroute from the Loopback0 interface of as3core1 to host1
headers = HeaderConstraints(dstIps='host1') #宛先のIP or ホスト名を指定
tracert = bf.q.traceroute(startLocation="as3core1[Loopback0]",  headers=headers).answer().frame() #開始ホスト名[開始ポート]を指定

show(tracert)
```
### 結果の見方
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507183/8c13a962-459f-33ba-4cdc-66b573e465c5.png)

Traces列にDenied_INと記載されており、最終的にdenyされることが分かります。
計4ルートでtracerouteが行われており、
どれもhost1で拒否されることが分かります。

# 3.configの差分の確認
2つのconfigの内容に違いがないかの確認をします。
なお、ここでいう内容の違いとは単なる記載の仕方の違いを指さず、
動作として違うもののみを表します。

## 3.0 下準備
読み込みたい2つのconfigを貼り付けます。
今回はoriginal_aclと、その圧縮版のcomposed_aclを読み込みます。

```python
original_acl = """
ip access-list acl
  10 deny icmp any any redirect
  20 permit udp 117.186.185.0/24 range 49152 65535 117.186.185.0/24 eq 3784
  30 permit udp 117.186.185.0/24 range 49152 65535 117.186.185.0/24 eq 3785
  40 permit tcp 11.36.216.170/32 11.36.216.169/32 eq bgp
  50 permit tcp 11.36.216.176/32 11.36.216.179/32 eq bgp
  60 permit tcp 204.150.33.175/32 204.150.33.83/32 eq bgp
  70 permit tcp 205.248.59.64/32 205.248.59.67/32 eq bgp
  80 permit tcp 205.248.58.190/32 205.248.58.188/32 eq bgp
  90 deny udp 10.10.10.42/32 218.8.104.58/32 eq domain
  100 permit udp 10.10.10.0/24 218.8.104.58/32 eq domain
  110 deny ip 54.0.0.0/8 any
  120 deny ip 163.157.0.0/16 any
  130 deny ip 166.144.0.0/12 any
  140 deny ip 198.170.50.0/24 any
  150 deny ip 198.120.0.0/16 any
  160 deny ip 11.36.192.0/19 any
  170 deny ip 11.125.64.0/19 any
  180 permit ip 166.146.58.184/32 any
  190 deny ip 218.66.57.0/24 any
  200 deny ip 218.66.56.0/24 any
  210 deny ip 218.67.71.0/24 any
  220 deny ip 218.67.72.0/24 any
  230 deny ip 218.67.96.0/22 any
  240 deny ip 8.89.120.0/22 any
  250 deny ip 54.203.159.1/32 any
  260 permit ip 218.8.104.0/25 any
  270 permit ip 218.8.104.128/25 any
  280 permit ip 218.8.103.0/24 any
  290 deny ip 144.49.45.40/32 any
  300 deny ip 163.255.18.63/32 any
  310 deny ip 202.45.130.141/32 any
  320 deny ip 212.26.132.18/32 any
  330 deny ip 218.111.16.132/32 any
  340 deny ip 218.246.165.90/32 any
  350 deny ip 29.228.179.210/32 any
  360 deny ip 194.181.135.214/32 any
  370 deny ip 10.64.90.249/32 any
  380 deny ip 207.70.46.217/32 any
  390 deny ip 219.185.241.117/32 any
  400 deny ip 2.80.3.219/32 any
  410 deny ip 27.212.145.150/32 any
  420 deny ip 131.159.53.215/32 any
  430 deny ip 214.220.213.107/32 any
  440 deny ip 196.64.84.239/32 any
  450 deny ip 28.69.250.136/32 any
  460 deny ip 200.45.87.238/32 any
  470 deny ip any 11.125.89.32/30
  480 deny ip any 11.125.89.36/30
  490 deny ip any 11.125.89.40/30
  500 deny ip any 11.125.89.44/30
  510 permit icmp any any echo-reply
  520 deny ip any 11.36.199.216/30
  530 deny ip any 11.36.199.36/30
  540 deny ip any 11.36.199.2/30
  550 deny ip any 11.36.199.52/30
  560 deny ip any 11.36.199.20/30
  570 deny ip any 11.125.82.216/30
  580 deny ip any 11.125.82.220/32
  590 deny ip any 11.125.82.36/30
  600 deny ip any 11.125.82.12/30
  610 deny ip any 11.125.80.136/30
  620 deny ip any 11.125.80.141/32
  630 deny ip any 11.125.87.48/30
  640 deny ip any 11.125.87.168/30
  650 deny ip any 11.125.87.173/32
  660 deny ip any 11.125.90.56/30
  670 deny ip any 11.125.90.240/30
  680 deny ip any 11.125.74.224/30
  690 deny ip any 11.125.91.132/30
  700 deny ip any 11.125.89.132/30
  710 deny ip any 11.125.89.12/30
  720 deny ip any 11.125.92.108/30
  730 deny ip any 11.125.92.104/32
  740 deny ip any 11.125.92.28/30
  750 deny ip any 11.125.92.27/32
  760 deny ip any 11.125.92.160/30
  770 deny ip any 11.125.92.164/32
  780 deny ip any 11.125.92.204/30
  790 deny ip any 11.125.92.202/32
  800 deny ip any 11.125.93.192/29
  810 deny ip any 11.125.95.204/30
  820 deny ip any 11.125.95.224/30
  830 deny ip any 11.125.95.180/30
  840 deny ip any 11.125.95.156/30
  850 deny tcp any any
  860 deny icmp any any
  870 deny udp any any
  880 deny ip any any
"""
```

```python
compressed_acl = """
ip access-list acl
  10 deny icmp any any redirect
  20 permit udp 117.186.185.0/24 range 49152 65535 117.186.185.0/24 range 3784 3785
! 30 MERGED WITH LINE ABOVE 
  40 permit tcp 11.36.216.170/32 11.36.216.169/32 eq bgp
  50 permit tcp 11.36.216.176/32 11.36.216.179/32 eq bgp
  60 permit tcp 204.150.33.175/32 204.150.33.83/32 eq bgp
  70 permit tcp 205.248.59.64/32 205.248.59.67/32 eq bgp
! 80 DECOMMISSIONED BGP SESSION
  90 deny udp 10.10.10.42/32 218.8.104.58/32 eq domain
  100 permit udp 10.10.10.0/24 218.8.104.58/32 eq domain
  110 deny ip 54.0.0.0/8 any
  120 deny ip 163.157.0.0/16 any
  130 deny ip 166.144.0.0/12 any
  140 deny ip 198.170.50.0/24 any
  150 deny ip 198.120.0.0/16 any
  160 deny ip 11.36.192.0/19 any
  170 deny ip 11.125.64.0/19 any
! 180 REMOVED UNREACHABLE LINE
  190 deny ip 218.66.56.0/23 any
! 200 MERGED WITH LINE ABOVE 
  210 deny ip 218.67.71.0/23 any
! 220 MERGED WITH LINE ABOVE  
  230 deny ip 218.67.96.0/22 any
  240 deny ip 8.89.120.0/22 any
! 250 REMOVED UNREACHABLE LINE
  260 permit ip 218.8.104.0/24 any
! 270 MERGED WITH LINE ABOVE
  280 permit ip 218.8.103.0/24 any
  290 deny ip 144.49.45.40/32 any
  300 deny ip 163.255.18.63/32 any
  310 deny ip 202.45.130.141/32 any
  320 deny ip 212.26.132.18/32 any
  330 deny ip 218.111.16.132/32 any
  340 deny ip 218.246.165.90/32 any
  350 deny ip 29.228.179.210/32 any
  360 deny ip 194.181.135.214/32 any
  370 deny ip 10.64.90.249/32 any
  380 deny ip 207.70.46.217/32 any
  390 deny ip 219.185.241.117/32 any
  400 deny ip 2.80.3.219/32 any
  410 deny ip 27.212.145.150/32 any
  420 deny ip 131.159.53.215/32 any
  430 deny ip 214.220.213.107/32 any
  440 deny ip 196.64.84.239/32 any
  450 deny ip 28.69.250.136/32 any
  460 deny ip 200.45.87.238/32 any
  470 deny ip any 11.125.89.32/28
  510 permit icmp any any echo-reply
! 520-870 REMOVED UNNECESSARY DENIES
  880 deny ip any any
"""
```

### 3.1 Config差分の確認

#### コード
```python
# Import packages 
%run startup.py
bf = Session(host="localhost")

# Initialize a snapshot with the original ACL
original_snapshot = bf.init_snapshot_from_text(
    original_acl, 
    platform="cisco-nx", 
    snapshot_name="original", 
    overwrite=True)

# Initialize a snapshot with the compressed ACL
compressed_snapshot = bf.init_snapshot_from_text(
    compressed_acl, 
    platform="cisco-nx", 
    snapshot_name="compressed", 
    overwrite=True)

# Now, compare the two ACLs in the two snapshots
answer = bf.q.compareFilters().answer(snapshot=compressed_snapshot, reference_snapshot=original_snapshot)
show(answer.frame())
```

#### 結果の見方
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507183/29516247-db67-a7a4-fe86-35478336e27c.png)

2つのConfigには3つの違いがあることが判明しました。
composed_aclの210行目が、original_aclの510行目の一部を拒否
composed_aclの510行目が、original_aclの220行目の一部を許可
composed_aclの880行目が、original_aclの80行目の一部を拒否

compressed_aclの210行目を見ると
```
210 deny ip 218.67.71.0/23 any
```

と記載されていますが、
original_aclの210行目、220行目を見ると
```
210 deny ip 218.67.71.0/24 any
220 deny ip 218.67.72.0/24 any
```
と記載されており、微妙に範囲が異なっていることが分かります。

:::note info
218.67.71.0/23　
⇒　218.67.70.0 ~ 218.67.71.255
210 deny ip 218.67.71.0/24 any
220 deny ip 218.67.72.0/24 any
⇒　218.67.71.0 ~ 218.67.72.255
:::

これが結果に出てきたようです。

# おわりに
本記事は公式のサンプルConfigを利用したものです。
面白い機能は様々ありますので、
是非公式のテキストも読んでみてください。