{# Macro import #}
{% from 'OPNsense/IPFW/rules.macro' import convert_address %}

#======================================================================================
# flush ruleset
#======================================================================================
flush

#======================================================================================
# general purpose rules 1...1000
#======================================================================================
add 100 allow pfsync from any to any
add 110 allow carp from any to any
# layer 2: pass ARP
add 120 pass layer2 mac-type arp,rarp
# OPNsense requires for WPA
add 130 pass layer2 mac-type 0x888e,0x88c7
# PPP Over Ethernet Session Stage/Discovery Stage
add 140 pass layer2 mac-type 0x8863,0x8864
# layer 2: block anything else non-IP(v4/v6)
add 150 deny layer2 not mac-type ip,ipv6

# allow traffic send from localhost
add 200 skipto 60000 ipv6 from ::1 to any
add 201 skipto 60000 ipv4 from 127.0.0.0/8 to any
add 202 skipto 60000 ipv6 from any to ::1
add 203 skipto 60000 ipv4 from any to 127.0.0.0/8

#======================================================================================
# traffic shaping section, authorized traffic
#======================================================================================
add 60000 return via any

{% if helpers.exists('OPNsense.TrafficShaper.rules.rule') %}
{% for rule in helpers.toList('OPNsense.TrafficShaper.rules.rule', 'sequence', 'int') %}
{%    if helpers.getUUIDtag(rule.target) in ['pipe','queue'] %}
{%        if  helpers.physical_interface(rule.interface) and rule.enabled|default('0') == '1' %}
{%            if helpers.getUUID(rule.target).enabled|default('0') == '1' %}
{%                if helpers.getUUIDtag(rule.target) == 'pipe' or
                     helpers.getUUID(helpers.getUUID(rule.target).pipe).enabled|default('0') == '1'
%}
{%                       if rule.interface2 and helpers.physical_interface(rule.interface2) %}
{#  2 interface defined, use both to match packets (2 rules)  #}
{%                         if rule.direction == 'in' or not rule.direction %}
add {{loop.index + 60000}} {{ helpers.getUUIDtag(rule.target) }} {{
    helpers.getUUID(rule.target).number }} {{ rule.proto.split('_')[0] }} from {%
    if rule.source_not|default('0') == '1' %}not {% endif %}{{ convert_address(rule, 'source') }} to {%
    if rule.destination_not|default('0') == '1' %}not {% endif %}{{convert_address(rule, 'destination')
    }} src-port  {{ rule.src_port }} dst-port {{ rule.dst_port }} recv {{
    helpers.physical_interface(rule.interface) }} {%
    if rule.proto.split('_')[1]|default('') == 'ack' %} {{ rule.proto.split('_')[2]|default('') }} tcpflags ack {% endif %}{%
    if rule.iplen|default('') != '' %} iplen 1-{{ rule.iplen }}{% endif %}{%
    if rule.dscp|default('') != '' %} dscp {{ rule.dscp }}{% endif %}
    xmit {{helpers.physical_interface(rule.interface2)
    }} // {{ (rule['@uuid'] + " " + rule.interface + " -> " + rule.interface2 + ": " + helpers.getUUID(rule.target).description)[0:78] }}
{%                         endif %}
{%                         if rule.direction == 'out' or not rule.direction %}
add {{loop.index + 60000}} {{ helpers.getUUIDtag(rule.target) }} {{
    helpers.getUUID(rule.target).number }} {{ rule.proto.split('_')[0] }} from {%
    if rule.source_not|default('0') == '1' %}not {% endif %}{{ convert_address(rule, 'source') }} to {%
    if rule.destination_not|default('0') == '1' %}not {% endif %}{{convert_address(rule, 'destination')
    }} src-port  {{ rule.src_port }} dst-port {{ rule.dst_port }} xmit {{
    helpers.physical_interface(rule.interface) }} {%
    if rule.proto.split('_')[1]|default('') == 'ack' %} {{ rule.proto.split('_')[2]|default('') }} tcpflags ack {% endif %}{%
    if rule.iplen|default('') != '' %} iplen 1-{{ rule.iplen }}{% endif %}{%
    if rule.dscp|default('') != '' %} dscp {{ rule.dscp }}{% endif %}
    recv {{helpers.physical_interface(rule.interface2)
    }} // {{ (rule['@uuid'] + " " + rule.interface2 + " -> " + rule.interface + ": " + helpers.getUUID(rule.target).description)[0:78] }}
{%                         endif %}
{%                       else %}
{#  normal, single interface situation  #}
add {{loop.index + 60000}} {{ helpers.getUUIDtag(rule.target) }} {{
    helpers.getUUID(rule.target).number }} {{ rule.proto.split('_')[0] }} from {%
    if rule.source_not|default('0') == '1' %}not {% endif %}{{ convert_address(rule, 'source') }} to {%
    if rule.destination_not|default('0') == '1' %}not {% endif %}{{convert_address(rule, 'destination')
    }} src-port  {{ rule.src_port }} dst-port {{ rule.dst_port }} {{rule.direction}} {%
    if rule.proto.split('_')[1]|default('') == 'ack' %}{{ rule.proto.split('_')[2]|default('') }} tcpflags ack {% endif %} {%
    if rule.iplen|default('') != '' %} iplen 1-{{ rule.iplen }}{% endif %}{%
    if rule.dscp|default('') != '' %} dscp {{ rule.dscp }}{% endif %} via {{
    helpers.physical_interface(rule.interface)
    }} // {{ (rule['@uuid'] + " " + rule.interface + ": " + helpers.getUUID(rule.target).description)[0:78] }}
{%                       endif %}
{%                   endif %}
{%            endif %}
{%        endif %}
{%    endif %}
{% endfor %}
{% endif %}

# pass authorized
add 65533 pass ip from any to any

# block all unmatched
add 65534 deny all from any to any
