{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Analyzing ACLs and firewall rules with Batfish" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Network and security engineers are responsible for ensuring that the ACLs and firewall rules in their networks are permitting and denying traffic as intended. This task usually requires manual checking or loading rulesets onto a lab device in order to test behavior on example packets of interest. These methods are not only time consuming but also error-prone. \n", "\n", "Batfish makes it easy to deeply analyze ACLs and firewall rules, which we generally call *filters.* It can show what a filter will do with a given packet, right down to the line of the filter that matches the packet; it can provide guarantees on how a filter treats a large space of packets; and it can sanity check a filter to ensure that every line in it matches at least some packets.\n", "\n", "In this notebook, we demonstrate these capabilities. In our [\"Provably Safe ACL and Firewall Changes\" notebook](https://github.com/batfish/pybatfish/blob/master/jupyter_notebooks/Provably%20Safe%20ACL%20and%20Firewall%20Changes.ipynb), we show how Batfish can guarantee that filter changes are safe.\n", "\n", "Check out a video demo of this notebook [here](https://youtu.be/KixQYEDh33s)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Initialization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We use an example network with two devices, a router with ACLs and a firewall. The device configurations can be seen [here](https://github.com/batfish/pybatfish/tree/master/jupyter_notebooks/networks/example-filters/current/configs). " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'current'" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Import packages\n", "%run startup.py\n", "bf = Session(host=\"localhost\")\n", "\n", "# Initialize a network and a snapshot\n", "bf.set_network(\"network-example-filters\")\n", "\n", "SNAPSHOT_NAME = \"current\"\n", "SNAPSHOT_PATH = \"networks/example-filters/current\"\n", "bf.init_snapshot(SNAPSHOT_PATH, name=SNAPSHOT_NAME, overwrite=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `testFilters`: Testing how filters treat a flow" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `testFilters` question shows what filters do with a particular flow and *why*. It takes as input the details of the flow and a set of filters to test. The answer provides a detailed view of how the flow is treated by each filter in the set.\n", "\n", "Flows are specified using source and destination IP addresses and, optionally, other fields such as IP protocols, ports, and TCP flags. You may also specify the ingress interface which is factored in when the behavior of a filter depends on it. See [documentation](https://pybatfish.readthedocs.io/en/latest/notebooks/filters.html#Test-Filters) for details. The question will fill in any unspecified fields with reasonable defaults.\n", "\n", "The set of filters to examine can be narrowed using various criteria, including regexes for node and filter names. Left unspecified, `testFilters` will give results for every filter in the network." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example 1: Test if hosts in a subnet can reach the DNS server" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Suppose we wanted to test if our ACL **acl_in** in router **rtr-with-acl** allows hosts in a subnet to reach our DNS server. This check is easily expressed. If the subnet is 10.10.10.0/24 and the DNS server is at the IP address 218.8.104.58, then the query will be as shown below, where we have picked 10.10.10.1 as a representative source IP for the subnet." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
| \n", " | Node | \n", "Filter_Name | \n", "Flow | \n", "Action | \n", "Line_Content | \n", "Trace | \n", "
|---|---|---|---|---|---|---|
| 0 | \n", "rtr-with-acl | \n", "acl_in | \n", "Start Location: rtr-with-acl Src IP: 10.10.10.1 Src Port: 49152 Dst IP: 218.8.104.58 Dst Port: 53 IP Protocol: UDP | \n",
" PERMIT | \n", "660 permit udp 10.10.10.0/24 218.8.104.58/32 eq domain | \n", "
| \n",
"
| \n", " | Node | \n", "Filter_Name | \n", "Flow | \n", "Action | \n", "Line_Content | \n", "Trace | \n", "
|---|---|---|---|---|---|---|
| 0 | \n", "firewall | \n", "~ZONE_OUTGOING_ACL~zone-z3~ | \n", "Start Location: firewall interface=GigabitEthernet0/0/2 Src IP: 10.114.64.1 Src Port: 49152 Dst IP: 10.114.60.10 Dst Port: 80 IP Protocol: TCP (SYN) | \n",
" DENY | \n", "no-match | \n", "
| \n", " | Node | \n", "Filter_Name | \n", "Flow | \n", "Action | \n", "Line_Content | \n", "Trace | \n", "
|---|---|---|---|---|---|---|
| 0 | \n", "rtr-with-acl | \n", "acl_in | \n", "Start Location: rtr-with-acl Src IP: 10.10.10.42 Src Port: 49152 Dst IP: 218.8.104.58 Dst Port: 53 IP Protocol: UDP | \n",
" DENY | \n", "460 deny udp 10.10.10.42/32 218.8.104.58/32 eq domain | \n", "
| \n",
"
| \n", " | Node | \n", "Filter_Name | \n", "Flow | \n", "Action | \n", "Line_Content | \n", "Trace | \n", "
|---|
| \n", " | Sources | \n", "Unreachable_Line | \n", "Unreachable_Line_Action | \n", "Blocking_Lines | \n", "Different_Action | \n", "Reason | \n", "Additional_Info | \n", "
|---|---|---|---|---|---|---|---|
| 1 | \n", "rtr-with-acl: acl_in | \n", "670 permit ip 166.146.58.184 any | \n", "PERMIT | \n", "540 deny ip 166.144.0.0/12 any | \n", "True | \n", "BLOCKING_LINES | \n", "None | \n", "
| 0 | \n", "rtr-with-acl: acl_in | \n", "790 deny ip 54.203.159.1/32 any | \n", "DENY | \n", "500 deny ip 54.0.0.0/8 any | \n", "False | \n", "BLOCKING_LINES | \n", "None | \n", "