此篇文章在github可以找到英文版的,此篇文章目的是提炼Batfish的用法
# Import packages and load questions
%run startup.py
load_questions()
# Assign a friendly name to your network and snapshot
NETWORK_NAME = "example_network"
SNAPSHOT_NAME = "example_snapshot"
SNAPSHOT_PATH = "networks/example"
# Now create the network and initialize the snapshot
bf_set_network(NETWORK_NAME)
bf_init_snapshot(SNAPSHOT_PATH, name=SNAPSHOT_NAME, overwrite=True)
# Load all questions
load_questions()
# To see available questions, you can use
# list_questions()
# You can also use tab-completion on the Batfish question module - bfq. -> press TAB key,
# uncomment and try on the following line
# bfq.
# In IPython and Jupyter you can use the "?" shorthand to get help on a question
?bfq.nodeProperties
# help(bfq.nodeProperties) # in standard Python console
parse_status = bfq.fileParseStatus().answer().frame()
# An example: use a filter on the returned dataframe to see which files failed to parse completely
parse_status[parse_status['Status'] != 'PASSED'] # change '!=' to '==' to get the files which passed
# View details if some of the files were not parsed completely
parse_warning = bfq.parseWarning().answer().frame()
parse_warning
# Extract the properties of all nodes whose names contain 'border'
node_properties = bfq.nodeProperties(nodes="/border/").answer().frame()
# View what columns (properties) are present in the answer
node_properties.columns
# To extract only a subset of properties, use the properties parameter
node_properties_trunc = bfq.nodeProperties(nodes="/border/", properties="Domain_Name|NTP_Servers|Interfaces").answer().frame()
node_properties_trunc
# Let's remove the interfaces column from our result
node_properties_trunc = node_properties_trunc[["Node", "Domain_Name", "NTP_Servers"]]
node_properties_trunc
# View only nodes with **23.23.23.23** as one of the configured ntp-servers
node_properties_trunc[node_properties_trunc['NTP_Servers'].apply(lambda x:'23.23.23.23' in x)]
interface_properties = bfq.interfaceProperties(nodes="/border/", properties="Interface_Type|Bandwidth|VRF|Primary_Address").answer().frame()
interface_properties[interface_properties['Primary_Address'].str.match("10.12", na=False)]
# List references to undefined structures
bfq.undefinedReferences().answer().frame()
# Get edges of type layer 3 (IP layer)
bfq.edges(nodes="as1border1", edgeType="layer3").answer().frame()
# Do a traceroute from host1 to 1.0.2.2
tr_frame = bfq.traceroute(startLocation="host1", headers=HeaderConstraints(dstIps="1.0.2.2")).answer().frame()
# Display results using customizations to handle large string values
show(tr_frame)
# Fetch the routing table of all VRFs on all nodes in the snapshot
routes_df = bfq.routes().answer().frame()
# View all routes for the network 90.90.90.0/24 with an AdminDistance of 0
routes_df[(routes_df['Network'] == "90.90.90.0/24") & (routes_df["Admin_Distance"] == 0)]
# Import packages and load questions
%run startup.py
load_questions()
# Initialize a network and snapshot
NETWORK_NAME = "example_network"
SNAPSHOT_NAME = "example_snapshot"
SNAPSHOT_PATH = "networks/example"
bf_set_network(NETWORK_NAME)
bf_init_snapshot(SNAPSHOT_PATH, name=SNAPSHOT_NAME, overwrite=True)
# Set the property that we want to extract
COL_NAME = "NTP_Servers"
# Extract NTP servers for all routers with 'border' in their name
node_props = bfq.nodeProperties(
nodes="/border/",
properties=COL_NAME).answer().frame()
node_props
(1)每个节点至少配置一个NTP服务
# Find nodes that have no NTP servers configured
ns_violators = node_props[node_props[COL_NAME].apply(
lambda x: len(x) == 0)]
ns_violators
(2)每个节点至少配置一个从引用集来的NTP服务
# Define the reference set of NTP servers
ref_ntp_servers = set(["23.23.23.23"])
# Find nodes that have no NTP server in common with the reference set
ns_violators = node_props[node_props[COL_NAME].apply(
lambda x: len(ref_ntp_servers.intersection(set(x))) == 0)]
ns_violators
(3)每个节点有NTP服务配置的引用集
# Find violating nodes whose configured NTP servers do not match the reference set
ns_violators = node_props[node_props[COL_NAME].apply(
lambda x: ref_ntp_servers != set(x))]
ns_violators
# Find extra and missing servers at each node
ns_extra = node_props[COL_NAME].map(lambda x: set(x) - ref_ntp_servers)
ns_missing = node_props[COL_NAME].map(lambda x: ref_ntp_servers - set(x))
# Join these columns up with the node columns for a complete view
diff_df = pd.concat([node_props["Node"],
ns_extra.rename('extra-{}'.format(COL_NAME)),
ns_missing.rename('missing-{}'.format(COL_NAME))],
axis=1)
diff_df
(4)每个节点都有匹配每一个节点数据库的NTP服务
# Transpose database data so each node has its own row
database_df = pd.DataFrame(data=database).transpose()
# Index on node for easier comparison
df_node_props = node_props.set_index('Node')
# Select only columns present in node_props (get rid of the extra dns-servers column)
df_db_node_props = database_df[df_node_props.columns].copy()
# Convert server lists into sets to support arithmetic below
df_node_props[COL_NAME] = df_node_props[COL_NAME].apply(set)
df_db_node_props[COL_NAME] = df_db_node_props[COL_NAME].apply(set)
# Figure out what servers are in the configs but not the database and vice versa
missing_servers = (df_db_node_props - df_node_props).rename(
columns={COL_NAME: 'missing-{}'.format(COL_NAME)})
extra_servers = (df_node_props - df_db_node_props).rename(
columns={COL_NAME: 'extra-{}'.format(COL_NAME)})
result = pd.concat([missing_servers, extra_servers], axis=1, sort=False)
# removing the index name for clearer output
del result.index.name
result
# Extract interface MTU for Ethernet0/0 interfaces on border routers
interface_mtu = bfq.interfaceProperties(
interfaces="/border/[Ethernet0/0]",
properties="MTU").answer().frame()
interface_mtu
Test how filters in the network treat a flow "testFilters"
Verify how filters treat a large space of flows "searchFilters
"
Find filter lines that will never match any packet "filterLineReachability
"
# Import packages and load questions
%run startup.py
load_questions()
# Initialize a network and a snapshot
bf_set_network("network-example-filters")
SNAPSHOT_NAME = "current"
SNAPSHOT_PATH = "networks/example-filters/current"
bf_init_snapshot(SNAPSHOT_PATH, name=SNAPSHOT_NAME, overwrite=True)
实例1:测试是否子网里的主机能够到到DNS服务器
# Check if a representative host can reach the DNS server
dns_flow = HeaderConstraints(srcIps="10.10.10.1",
dstIps="218.8.104.58",
applications=["dns"])
answer = bfq.testFilters(headers=dns_flow,
nodes="rtr-with-acl",
filters="acl_in").answer()
show(answer.frame())
实例2:测试HTTP流不能从一个区域到另一个区域
# Test if a host can reach the DNS server
http_flow = HeaderConstraints(srcIps="10.114.64.1",
dstIps="10.114.60.10",
applications=["http"])
answer = bfq.testFilters(headers=http_flow,
startLocation="@enter(firewall[GigabitEthernet0/0/2])",
filters="@out(GigabitEthernet0/0/3)").answer()
show(answer.frame())
Example1:searchFilters
: Verifying how filters treat a (very large) space of flows
# Check if the subnet can reach the DNS server
dns_traffic = HeaderConstraints(srcIps="10.10.10.0/24",
dstIps="218.8.104.58",
applications=["dns"])
answer = bfq.searchFilters(headers=dns_traffic,
action="deny",
filters="acl_in").answer()
show(answer.frame())
Example 2: Verify that the only TCP traffic that can go from one zone to another is NFS traffic
# Check if any non-NFS, TCP flow can go from one zone to another
non_nsf_tcp_traffic = HeaderConstraints(srcIps="101.164.101.231",
dstIps="101.164.9.0/24",
ipProtocols=["tcp"],
dstPorts="!2049") # exclude NFS port (2049)
answer = bfq.searchFilters(headers=non_nsf_tcp_traffic,
startLocation="@enter(firewall[GigabitEthernet0/0/2])",
filters="@out(GigabitEthernet0/0/3)",
action="permit").answer()
show(answer.frame())
# Find unreachable lines in filters of rtr-with-acl
aclAns = bfq.filterLineReachability(nodes="rtr-with-acl").answer()
show(aclAns.frame())