> For the complete documentation index, see [llms.txt](https://jncia-workbook.gitbook.io/workbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jncia-workbook.gitbook.io/workbook/junos-firewall-filters/1-basic-firewall-filters.md).

# 1) Basic Firewall Filters

### Pre-Work

Load the config called **ospf.configured.cfg** using the **load\_config\_on\_nodes.py** script.

```
python3 load_config_on_nodes.py --lab_dir three-routers --config_filename ospf.configured.cfg
```

### Lab

OSPFv2 and OSPFv3 are fully setup.

Configure R2 to drop traffic as follows:

* On `ge-0/0/0`, drop inbound traffic destined for R2's local interface addresses: `10.1.2.2` and `2001:db8:1:2::2`
  * However, make sure OSPF traffic is not dropped

All other traffic should be allowed through.

### Answer

<details>

<summary>Expand to reveal</summary>

```
edit firewall family inet filter ge-0/0/0_filter_in_v4
set term allow_ospf from protocol ospf
set term allow_ospf then accept
set term block_local_address from destination-address 10.1.2.2/32
set term block_local_address then discard
set term allow_all then accept

top edit firewall family inet6 filter ge-0/0/0_filter_in_v6
set term allow_ospf from next-header ospf
set term allow_ospf then accept
set term block_local_address from destination-address 2001:db8:1:2::2/128
set term block_local_address then discard
set term allow_all then accept

top
set interfaces ge-0/0/0.0 family inet filter input ge-0/0/0_filter_in_v4
set interfaces ge-0/0/0.0 family inet6 filter input ge-0/0/0_filter_in_v6
```

</details>

### Explanation

<details>

<summary>Expand to reveal</summary>

Firewall filters are stateless ACLs, which can be applied to interfaces just like IOS ACLs. In Junos, firewall filters are configured under the `firewall` configuration hierarchy, while stateful firewall policies, such as on a SRX, are configured under the `security` hierarchy.

\
Firewall filters use syntax that is similar to RPLs on IOS-XR, if you are familiar with those. The general concept is that you use `if`/`then` statements to match traffic and take some action. The ability to have multiple match statements and use CIDR notation (instead of wildcard masks) makes filters quite intuitive. Having a good understanding of how filters work is very important, as similar syntax is used for routing policies as well. (Firewall filters and route policies are different things, but syntax is similar).

\
You use `from` to match attributes of the packet, and `then` to define the action. These go under a `term`. Multiple terms are configured under a filter. Also note that a filter is defined under a particular `family`, for example `inet` or `inet6`.

```
edit firewall family inet filter ge-0/0/0_filter_in_v4
set term allow_ospf from protocol ospf
set term allow_ospf then accept
```

\
Above, the first term is called `allow_ospf` and matches OSPF protocol traffic (IP protocol 89) and accepts/permits it.

\
You can essentially match on any aspect of the packet. For example:

* src/dst L3 address
* src/dst L4 port
* DSCP/IP Precedence value
* TCP flags
* IP protocol value
  * Note that for IPv4, you match `protocol`, and for IPv6, you match `next-header`
* IP options
* Packet length
* TTL value
* and more...

\
You can have multiple `match` statements, and all must match for the packet to match the given term. For example, this must match both source address 10.1.1.1 and destination-port ssh (22):

```
set firewall family inet filter EXAMPLE term MULTIPLE_MATCH from source-address 10.1.1.1    
set firewall family inet filter EXAMPLE term MULTIPLE_MATCH from destination-port ssh   
```

\
You can also have multiple values on a single `match` statement. In that case, it is a logical `OR` operation, in which only one value needs to match. For example, this term matches either ICMP or TCP traffic:

```
set firewall family inet filter EXAMPLE term MULTIPLE_MATCH from protocol [ icmp tcp ]
```

\
Basic `then` actions include:

* `discard` (silently drop)
* `reject` (send ICMP unreachable)
* `accept`

\
The above actions are all *terminating* actions, meaning that when used, the processing terminates at that term. We will look at *non-terminating* actions in an upcoming lab.

\
Terms are evaluated from the top down, and there is an implicit discard-all at the end. For this reason we need to add an explicit allow-all term at the end to satisfy the task requirements. Note that if there is no `from` statement, then that term matches all traffic.

```
edit firewall family inet filter ge-0/0/0_filter_in_v4
set term allow_ospf from protocol ospf
set term allow_ospf then accept
set term block_local_address from destination-address 10.1.2.2/32
set term block_local_address then discard
set term allow_all then accept  <---------------
```

\
Generally, firewall configuration is easier to visualize in the hierarchical  format:

```
admin@R2> show configuration firewall 
family inet {
    filter ge-0/0/0_filter_in_v4 {
        term allow_ospf {
            from {
                protocol ospf;
            }
            then accept;
        }
        term block_local_address {
            from {
                destination-address {
                    10.1.2.2/32;
                }
            }
            then {
                discard;
            }
        }
        term allow_all {
            then accept;
        }
    }
}
family inet6 {
    filter ge-0/0/0_filter_in_v6 {
        term allow_ospf {
            from {
                next-header ospf;
            }
            then accept;
        }
        term block_local_address {
            from {
                destination-address {
                    2001:db8:1:2::2/128;
                }
            }
            then discard;
        }
        term allow_all {
            then accept;
        }
    }
}
```

\
When trying to view the config in **set** format, it can be problematic because the syntax is so verbose:

```
admin@R2> show configuration firewall family inet filter ge-0/0/0_filter_in_v4 | display set 
set firewall family inet filter ge-0/0/0_filter_in_v4 term allow_ospf from protocol ospf
set firewall family inet filter ge-0/0/0_filter_in_v4 term allow_ospf then accept
set firewall family inet filter ge-0/0/0_filter_in_v4 term block_local_address from destination-address 10.1.2.2/32
set firewall family inet filter ge-0/0/0_filter_in_v4 term block_local_address then discard
set firewall family inet filter ge-0/0/0_filter_in_v4 term allow_all then accept
```

\
To make this easier, we can show configuration of the particular filter, and then pipe to `| display set relative`:

```
admin@R2> show configuration firewall family inet filter ge-0/0/0_filter_in_v4 | display set relative 
set term allow_ospf from protocol ospf
set term allow_ospf then accept
set term block_local_address from destination-address 10.1.2.2/32
set term block_local_address then discard
set term allow_all then accept
```

\
Firewall filters are either applied ingress (`input`) or egress (`output`). The task asks us to drop traffic inbound, so we apply the filters to the interface in the `input` direction:

```
set interfaces ge-0/0/0.0 family inet filter input ge-0/0/0_filter_in_v4
set interfaces ge-0/0/0.0 family inet6 filter input ge-0/0/0_filter_in_v6
```

\
By default, the system will not count or log any hits on the firewall rules, so we are a bit limited with CLI verification. We can see that the filters are applied to the interface with the below show command:

```
admin@R2> show interfaces ge-0/0/0.0 detail | match "Protocol|Filters" 
    Protocol inet, MTU: 1500
      Input Filters: ge-0/0/0_filter_in_v4
    Protocol inet6, MTU: 1500
      Input Filters: ge-0/0/0_filter_in_v6
```

\
We can also see this information with `show interfaces filters`:

```
admin@R2> show interfaces filters 
Interface       Admin Link Proto Input Filter         Output Filter
ge-0/0/0        up    up  
ge-0/0/0.0      up    up   inet  ge-0/0/0_filter_in_v4
                           inet6 ge-0/0/0_filter_in_v6

<snip>
```

\
We should see that R1 cannot ping R2's local addresses on `ge-0/0/0`, but should still be able to ping R2's loopback and R3.

```
admin@R1> ping 10.1.2.2 
PING 10.1.2.2 (10.1.2.2): 56 data bytes
^C
--- 10.1.2.2 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss

admin@R1> ping 2001:db8:1:2::2 
PING6(56=40+8+8 bytes) 2001:db8:1:2::1 --> 2001:db8:1:2::2
^C
--- 2001:db8:1:2::2 ping6 statistics ---
1 packets transmitted, 0 packets received, 100% packet loss

admin@R1> ping 2.2.2.2 
PING 2.2.2.2 (2.2.2.2): 56 data bytes
64 bytes from 2.2.2.2: icmp_seq=0 ttl=64 time=1.964 ms

admin@R1> ping 3.3.3.3 
PING 3.3.3.3 (3.3.3.3): 56 data bytes
64 bytes from 3.3.3.3: icmp_seq=0 ttl=63 time=2.342 ms
```

</details>

### Further Reading

<https://www.youtube.com/watch?v=7LXFonmAKk0&list=PLDQaRcbiSnqHAGz-wapjtd3zQxUg-a8dU&index=14>

<https://www.networkfuntimes.com/a-beginners-guide-to-junos-firewall-filters/>

<https://www.juniper.net/documentation/us/en/software/junos/routing-policy/topics/concept/firewall-filter-stateless-overview.html>
