Sfoglia il codice sorgente

Merge pull request #117 from vycontrol/b20.05.10

B20.05.10
Roberto Bertó 5 anni fa
parent
commit
90e45dff9e

+ 1 - 0
requirements.txt

@@ -3,3 +3,4 @@ Django==3.0.7
 pytz==2019.3
 sqlparse==0.3.1
 requests
+python-slugify

+ 5 - 1
vycontrol/filters/vycontrol_filters.py

@@ -1,6 +1,6 @@
 from django.template.defaultfilters import register
 import random
-
+import pprint
 
 @register.filter
 def routepack(value): 
@@ -35,3 +35,7 @@ def random_int(a, b=None):
     if b is None:
         a, b = 0, a
     return random.randint(a, b)
+
+#@register.filter
+#def pretty(s):
+#    return pprint.pformat(s, indent=4, width=120),

+ 80 - 0
vycontrol/firewall/templates/firewall/zones-addrule.html

@@ -0,0 +1,80 @@
+{% extends "base.html" %}
+
+{% block header_title %}Add Firewall Ruleset to Zone{% endblock %}
+{% block section_title %}Add Firewall Ruleset to Zone{% endblock %}
+{% block username %}{{ username }}{% endblock %}
+
+{% block debug %}
+
+<h3>interfaces</h3>
+{{ interfaces|pprint }}
+
+<h3>interfaces_all_names</h3>
+{{ interfaces_all_names|pprint }}
+
+<h3>zones</h3>
+{{ zones|pprint }}
+
+<h4>firewalls</h4>
+{{ firewalls|pprint }}
+
+{% endblock %}
+
+{% block content %}
+
+<p class="submenu1">
+    <a href="{% url 'firewall:firewall-list' %}">Firewall List</a> | 
+    <a href="{% url 'firewall:firewall-create' %}">Create new firewall</a> | 
+    <a href="{% url 'firewall:firewall-addressgroup-list' %}">Address Group</a> | 
+    <a href="{% url 'firewall:firewall-networkgroup-list' %}">Network Group</a> | 
+    <a href="{% url 'firewall:firewall-portgroup-list' %}">Port Group</a> | 
+    <a href="{% url 'firewall:firewall-zones' %}">Zones</a>
+</p>
+
+<h3>Add zone ruleset</h3>
+<form action="{% url 'firewall:firewall-zones-addrule' %}" method="post">
+    {% csrf_token %}
+
+    <p>
+        <input type="checkbox" name="reverse" id="reverse" value="1">
+        <label for="alias">create reverse ruleset (from source to destination) </label>
+    </p>        
+
+    <p>
+        <label for="dstzone">destination zone - single choice</label><br>
+        <select name="dstzone" id="dstzone" size="5" style="width: 200px;">
+            {% for zone in zones %}
+            <option value="{{ zone }}">{{ zone }}</option>
+            {% endfor %}
+        </select>
+    </p>
+
+
+    <p>
+        <label for="srczone">from zone - single choice</label><br>
+        <select name="srczone" id="srczone" size="5" style="width: 200px;">
+            {% for zone in zones %}
+            <option value="{{ zone }}">{{ zone }}</option>
+            {% endfor %}
+        </select>
+    </p>
+
+
+    <p>
+        <label for="firewall">firewall name - single choice</label><br>
+        <select name="firewall" id="firewall" size="5" style="width: 200px;">
+            {% for firewall in firewalls %}
+            <option value="{{ firewall }}">{{ firewall }}</option>
+            {% endfor %}
+        </select>
+
+    </p>
+
+    <p>
+        <input type="submit" value="Add zone ruleset">
+    </p>
+
+{% endblock %}
+
+
+

+ 97 - 81
vycontrol/firewall/templates/firewall/zones-edit.html

@@ -6,18 +6,32 @@
 
 {% block debug %}
 
-{{ zoneinfo }}
+<h3>interfaces_zone_alias</h3>
+{{ interfaces_zone_alias|pprint }}
 
+<h3>interfaces_other</h3>
+{{ interfaces_zone_alias_other|pprint }}
 
-{{ allzones }}
+<h3>interfaces_defined</h3>
+{{ interfaces_defined|pprint}}
 
-{{ interfaces_defined }}
+<h3>interfaces_defined_form</h3>
+{{ interfaces_defined_form|pprint}}
 
-{{ interfaces_zone }}
+<h3>allzones</h3>
+{{ allzones|pprint }}
 
-{{ interfaces_pretty }}
+<h3>interfaces</h3>
+{{ interfaces|pprint }}
 
-{{ interfaces_all_names_pretty }}
+<h3>interfaces_all_names</h3>
+{{ interfaces_all_names|pprint }}
+
+<h3>interfaces_all_names_dict</h3>
+{{ interfaces_all_names_dict|pprint }}
+
+<h3>zoneinfo</h3>
+{{ zoneinfo|pprint }}
 
 {% endblock %}
 
@@ -34,91 +48,93 @@
 
 
 {% if exists == True %} 
-    {% if form_added == False %}
-        <h3>Edit zone {{ zonename }}</h3>
+    <h3>Edit zone {{ zonename }}</h3>
 
-        <form action="{% url 'firewall:firewall-zones-add' %}" method="post">
-            {% csrf_token %}
-        
-            <p>
-                <label for="alias">name</label><br>
-                <input type="text" name="name" id="name" value="" size="60">
-            </p>    
-
-            <p>
-                <label for="alias">description</label><br>
-                <input type="text" name="description" id="description" value="" size="60">
-            </p>    
-            
-            <p>
-                <label for="hostname">default action</label><br>
-                <input type="radio" name="action" id="action" value="drop" {% if firewall.defaultaction == "drop" %}checked="checked"{% endif %}> drop
-                <input type="radio" name="action" id="action" value="reject" {% if firewall.defaultaction == "accept" %}checked="checked"{% endif %}> reject        
-            </p>
-
-            {% comment %}
-            <h2>Local-zone</h2>
-            <p>Local zones cannot bellong to any other interface and will be applied to the router itself.<br>
-                <input type="checkbox" name="localzone" value="1" id="localzone">
-                <label for="localzone">set as local-zone</label><br>
-            </p> 
-            {% endcomment %}
+    <form action="{% url 'firewall:firewall-zones-edit' zonename %}" method="post">
+        <input type="hidden" name="form_changed" value="1">
 
+        {% csrf_token %}
 
 
+        <p>
+            <label for="alias">description</label><br>
+            <input type="text" name="description" id="description" value="{{ zoneinfo.description }}" size="60">
+        </p>    
         
-
-
-            <div id="interfacesdiv">
-                <h2>Interfaces to apply</h2>
-                        {% for iface in interfaces_all_names %}
-                            {% if iface.type != "loopback" %}
-                                {% if iface.vif %}
-                                    {% with iface_id="interface_"|add:iface.interface_name|add:"."|add:iface.vif iface_js="interface_"|add:iface.interface_name|add:"_"|add:iface.vif  %}
-                                        {% if iface_id not in interfaces_defined_form %}
-                                            <input type="checkbox" name="{{ iface_id }}" value="{{ iface_id  }}" id="{{ iface_js }}">
-                                            <label for="{{ iface_id }}">{{ iface.type }} {{ iface.interface_name }}{% if iface.vif %}.{{ iface.vif }}{% endif %}</label><br>
-                                        {% else %}
-                                            <input type="checkbox" name="{{ iface_id }}" value="{{ iface_id  }}" id="{{ iface_js }}" disabled>
-                                            <label for="{{ iface_id }}">{{ iface.type }} {{ iface.interface_name }}{% if iface.vif %}.{{ iface.vif }}{% endif %} belongs to another zone</label><br>                            
-                                        {% endif %}
-                                    {% endwith %}
-                                {% else %}
-                                    {% with iface_id="interface_"|add:iface.interface_name iface_js="interface_"|add:iface.interface_name %}
-                                        {% if iface_id not in interfaces_defined_form %}
-                                            <input type="checkbox" name="{{ iface_id }}" value="{{ iface_id  }}" id="{{ iface_js }}">
-                                            <label for="{{ iface_id }}">{{ iface.type }} {{ iface.interface_name }}{% if iface.vif %}.{{ iface.vif }}{% endif %}</label><br>
-                                        {% else %}
-                                            <input type="checkbox" name="{{ iface_id }}" value="{{ iface_id  }}" id="{{ iface_js }}" disabled>
-                                            <label for="{{ iface_id }}">{{ iface.type }} {{ iface.interface_name }}{% if iface.vif %}.{{ iface.vif }}{% endif %} belongs to another zone</label><br>
-                                        {% endif %}
-                                    {% endwith %}                    
-                                {% endif %}
+        <p>
+            <label for="hostname">default action</label><br>
+            <input type="radio" name="action" id="action" value="drop" {% if zoneaction == "drop" %}checked="checked"{% endif %}> drop
+            <input type="radio" name="action" id="action" value="reject" {% if zoneaction == "reject" %}checked="checked"{% endif %}> reject        
+        </p>
+
+        {% comment %}
+        <h2>Local-zone</h2>
+        <p>Local zones cannot bellong to any other interface and will be applied to the router itself.<br>
+            <input type="checkbox" name="localzone" value="1" id="localzone">
+            <label for="localzone">set as local-zone</label><br>
+        </p> 
+        {% endcomment %}
+
+
+
+    
+
+
+        <div id="interfacesdiv">
+            <h2>Interfaces to apply</h2>
+                    {% for iface in interfaces_all_names %}
+                        {% if iface.type != "loopback" %}
+                            {% if iface.vif %}
+                                {% with iface_id="interface_"|add:iface.interface_name|add:"."|add:iface.vif iface_js="interface_"|add:iface.interface_name|add:"_"|add:iface.vif iface_alias=iface.interface_name|add:"."|add:iface.vif %}
+                                    {% if iface_id in interfaces_zone_alias %}
+                                        <input type="checkbox" name="{{ iface_id }}" value="{{ iface_id  }}" id="{{ iface_js }}" checked> 
+                                        <label for="{{ iface_id }}">{{ iface.type }} {{ iface.interface_name }}{% if iface.vif %}.{{ iface.vif }}{% endif %}</label><br>
+                                    {% elif iface_id in interfaces_zone_alias_other %}
+                                        <input type="checkbox" name="{{ iface_id }}" value="{{ iface_id  }}" id="{{ iface_js }}" disabled>  
+                                        <label for="{{ iface_id }}">{{ iface.type }} {{ iface.interface_name }}{% if iface.vif %}.{{ iface.vif }}{% endif %} belongs to another zone</label><br>                            
+                                    {% else %}
+                                        <input type="checkbox" name="{{ iface_id }}" value="{{ iface_id  }}" id="{{ iface_js }}">
+                                        <label for="{{ iface_id }}">{{ iface.type }} {{ iface.interface_name }}{% if iface.vif %}.{{ iface.vif }}{% endif %}</label><br>
+                                    {% endif %}
+                                {% endwith %}
+                            {% else %}
+                                {% with iface_id="interface_"|add:iface.interface_name iface_js="interface_"|add:iface.interface_name  iface_alias=iface.interface_name %}
+                                    {% if iface_id in interfaces_zone_alias %}
+                                        <input type="checkbox" name="{{ iface_id }}" value="{{ iface_id  }}" id="{{ iface_js }}" checked> 
+                                        <label for="{{ iface_id }}">{{ iface.type }} {{ iface.interface_name }}{% if iface.vif %}.{{ iface.vif }}{% endif %}</label><br>
+                                    {% elif iface_id in interfaces_zone_alias_other %}
+                                        <input type="checkbox" name="{{ iface_id }}" value="{{ iface_id  }}" id="{{ iface_js }}" disabled>  
+                                        <label for="{{ iface_id }}">{{ iface.type }} {{ iface.interface_name }}{% if iface.vif %}.{{ iface.vif }}{% endif %} belongs to another zone</label><br>                                        
+                                    {% else %}
+                                        <input type="checkbox" name="{{ iface_id }}" value="{{ iface_id  }}" id="{{ iface_js }}"> 
+                                        <label for="{{ iface_id }}">{{ iface.type }} {{ iface.interface_name }}{% if iface.vif %}.{{ iface.vif }}{% endif %}</label><br>
+                                    {% endif %}
+                                {% endwith %}                    
                             {% endif %}
-                        {% endfor %}
-            </div>    
-            
-
-            
-            <input type="submit" value="Add Firewall">
-        </form>
-
+                        {% endif %}
+                    {% endfor %}
+        </div>    
+        
 
         
-        <script>
-            $(document).ready(function () {                            
-                $("#localzone").change(function () {
-                    if ($("#localzone").is(":checked")) {
-                        $('#interfacesdiv').hide();
-                    }
-                    else if ($("#localzone").not(":checked")) {
-                        $('#interfacesdiv').show();
-                    }
-                });
+        <input type="submit" value="Edit Zone">
+    </form>
+
+
+    
+    <script>
+        $(document).ready(function () {                            
+            $("#localzone").change(function () {
+                if ($("#localzone").is(":checked")) {
+                    $('#interfacesdiv').hide();
+                }
+                else if ($("#localzone").not(":checked")) {
+                    $('#interfacesdiv').show();
+                }
             });
+        });
 
-        </script>
-    {% endif %}
+    </script>
 {% endif %}
 
 

+ 36 - 0
vycontrol/firewall/templates/firewall/zones-remove.html

@@ -0,0 +1,36 @@
+{% extends "base.html" %}
+
+{% block header_title %}Remove Firewall Zone{% endblock %}
+{% block section_title %}Remove Firewall Zone{% endblock %}
+{% block username %}{{ username }}{% endblock %}
+
+{% block debug %}
+
+<h3>interfaces</h3>
+{{ interfaces|pprint }}
+
+<h3>interfaces_all_names</h3>
+{{ interfaces_all_names|pprint }}
+
+<h3>zoneinfo</h3>
+{{ zoneinfo|pprint }}
+
+{% endblock %}
+
+{% block content %}
+
+<p class="submenu1">
+    <a href="{% url 'firewall:firewall-list' %}">Firewall List</a> | 
+    <a href="{% url 'firewall:firewall-create' %}">Create new firewall</a> | 
+    <a href="{% url 'firewall:firewall-addressgroup-list' %}">Address Group</a> | 
+    <a href="{% url 'firewall:firewall-networkgroup-list' %}">Network Group</a> | 
+    <a href="{% url 'firewall:firewall-portgroup-list' %}">Port Group</a> | 
+    <a href="{% url 'firewall:firewall-zones' %}">Zones</a>
+</p>
+
+
+
+{% endblock %}
+
+
+

+ 36 - 0
vycontrol/firewall/templates/firewall/zones-removerule.html

@@ -0,0 +1,36 @@
+{% extends "base.html" %}
+
+{% block header_title %}Remove Firewall Zone Rule{% endblock %}
+{% block section_title %}Remove Firewall Zone Rule{% endblock %}
+{% block username %}{{ username }}{% endblock %}
+
+{% block debug %}
+
+<h3>interfaces</h3>
+{{ interfaces|pprint }}
+
+<h3>interfaces_all_names</h3>
+{{ interfaces_all_names|pprint }}
+
+<h3>zoneinfo</h3>
+{{ zoneinfo|pprint }}
+
+{% endblock %}
+
+{% block content %}
+
+<p class="submenu1">
+    <a href="{% url 'firewall:firewall-list' %}">Firewall List</a> | 
+    <a href="{% url 'firewall:firewall-create' %}">Create new firewall</a> | 
+    <a href="{% url 'firewall:firewall-addressgroup-list' %}">Address Group</a> | 
+    <a href="{% url 'firewall:firewall-networkgroup-list' %}">Network Group</a> | 
+    <a href="{% url 'firewall:firewall-portgroup-list' %}">Port Group</a> | 
+    <a href="{% url 'firewall:firewall-zones' %}">Zones</a>
+</p>
+
+
+
+{% endblock %}
+
+
+

+ 39 - 3
vycontrol/firewall/templates/firewall/zones.html

@@ -7,6 +7,10 @@
 {% block debug %}
 
 {{ allzones_pretty }}
+
+<h3>allzonesrules</h3>
+{{ allzonesrules|pprint }} 
+
 {% endblock %}
 
 {% block content %}
@@ -19,7 +23,8 @@
     <a href="{% url 'firewall:firewall-portgroup-list' %}">Port Group</a>
 </p>
 <p class="submenu2">
-    <a href="{% url 'firewall:firewall-zones-add' %}">Add Zone</a>
+    <a href="{% url 'firewall:firewall-zones-add' %}">Add Zone</a> | 
+    <a href="{% url 'firewall:firewall-zones-addrule' %}">Add Ruleset</a> 
 </p>
 
 
@@ -29,13 +34,16 @@
 
     <table border="1" width="100%">
     <tr>
-        <th>zone</th>
-        <th>description</th>
+        <th width="25%">zone</th>
+        <th width="50%">description</th>
+        <th width="25%">action</th>
+    </tr>
     </tr>    
     {% for zone in allzones %}
         <tr>
         <td><a href="{% url 'firewall:firewall-zones-edit' zone.name %}">{{ zone.name }}</a></td>
         <td>{{ zone.description }}</td>
+        <td><a href="{% url 'firewall:firewall-zones-remove' zone.name %}">remove</a></td>
         </tr>
     {% endfor %}
 
@@ -46,6 +54,34 @@
 {% endif %}    
 
 
+<h3>Firewall Zones Rules</h3>
+
+{% if allzonesrules %}
+
+    <table border="1" width="100%">
+    <tr>
+        <th width="25%">zone destination</th>
+        <th width="25%">zone source</th>
+        <th width="25%">firewall</th>
+        <th width="25%">action</th>
+    </tr>
+    </tr>    
+    {% for rule in allzonesrules %}
+        <tr>
+            <td>{{ rule.dstzone }}</td>
+            <td>{{ rule.srczone }}</td>
+            <td>{{ rule.firewall }}</td>
+            <td><a href="{% url 'firewall:firewall-zones-removerule' rule.dstzone rule.srczone rule.firewall %}">remove</a></td>
+        </tr>
+    {% endfor %}
+
+    </table>
+
+{% else %}
+<p>No firewall zone rules exists.</p>
+{% endif %}    
+
+
 {% endblock %}
 
 

+ 4 - 1
vycontrol/firewall/urls.py

@@ -32,7 +32,10 @@ urlpatterns = [
 
     path('zones', views.firewall_zones, name='firewall-zones'),
     path('zones/add', views.firewall_zones_add, name='firewall-zones-add'),
-    path('zones/edit<str:zonename>', views.firewall_zones_edit, name='firewall-zones-edit'),
+    path('zones/addrule', views.firewall_zones_addrule, name='firewall-zones-addrule'),
+    path('zones/removerule/<str:dstzone>/<str:srczone>/<str:firewall>', views.firewall_zones_removerule, name='firewall-zones-removerule'),
+    path('zones/edit/<str:zonename>', views.firewall_zones_edit, name='firewall-zones-edit'),
+    path('zones/remove/<str:zonename>', views.firewall_zones_remove, name='firewall-zones-remove'),
 
 
     path('addrule/<str:firewall_name>', views.addrule, name='addrule'),

+ 366 - 86
vycontrol/firewall/views.py

@@ -12,7 +12,7 @@ import vycontrol_vyos_api_lib as vapilib
 import vycontrol_vyos_api as vapi
 import vycontrol_messages as vmsg
 
-
+from slugify import slugify
 from performance import timer
 from perms import is_authenticated
 import perms
@@ -33,16 +33,16 @@ def index(request):
     #interfaces = vyos.get_interfaces()
     all_instances = vyos.instance_getall_by_group(request)
     hostname_default = vyos.get_hostname_prefered(request)
+    msg = vmsg.msg()
 
 
-    firewall2 = vapilib.api(
+    """firewall2 = vapilib.api(
         hostname =      hostname_default,
         api =           'get',
         op =            'showConfig',
         cmd =           {"op": "showConfig", "path": ["firewall"]},
         description =   "get all firewall",
-    )
-
+    )"""
 
 
     is_superuser = perms.get_is_superuser(request.user)
@@ -61,11 +61,12 @@ def index(request):
     template = loader.get_template('firewall/list.html')
     context = { 
         #'interfaces': interfaces,
-        'instances': all_instances,
-        'hostname_default': hostname_default,
-        'firewall_all':  firewall_all,
-        'username': request.user,
-        'is_superuser' : is_superuser,
+        'instances':                                all_instances,
+        'hostname_default':                         hostname_default,
+        'firewall_all':                             firewall_all,
+        'username':                                 request.user,
+        'is_superuser' :                            is_superuser,
+        'msg' :                                     msg,
     }   
     return HttpResponse(template.render(context, request))
 
@@ -1572,6 +1573,7 @@ def firewall_zones(request):
     interfaces_defined_form     = []
     interfaces_zone             = {}
     allzones                    = []
+    allzonesrules               = []
 
     if get_firewall_zones.success:
         allzones = get_firewall_zones.data
@@ -1582,9 +1584,21 @@ def firewall_zones(request):
                         interfaces_defined.append(zoneinterface)
                         interfaces_defined_form.append("interface_" + zoneinterface)
                         interfaces_zone[zoneinterface] = zone
+                if 'from' in allzones['zone'][zone]:
+                    zonerule = {}
+                    zonerule['dstzone'] = zone
 
+                    for zonesrc in allzones['zone'][zone]['from']:
+                        zonerule['srczone'] =       zonesrc
+
+                        if 'firewall' in allzones['zone'][zone]['from'][zonesrc]:
+                            if 'name' in allzones['zone'][zone]['from'][zonesrc]['firewall']:
+                                zonerule['firewall'] =       allzones['zone'][zone]['from'][zonesrc]['firewall']['name']
+
+                    allzonesrules.append(zonerule)
+
+                    
 
-    
     if 'zone' in allzones:
         allzones2 = []
         for zone in allzones['zone']:
@@ -1602,12 +1616,11 @@ def firewall_zones(request):
         'is_superuser' :                            is_superuser,
         'allzones':                                 allzones2,
         'allzones_pretty':                          pprint.pformat(allzones2, indent=4, width=120),
+        'allzonesrules' :                           allzonesrules,
 
     }   
     return HttpResponse(template.render(context, request))
 
-
-
 @is_authenticated
 def firewall_zones_add(request):
     msg = vmsg.msg()
@@ -1652,7 +1665,7 @@ def firewall_zones_add(request):
                 valid = True
                 msg.add_success("Local-zone defined")       
             else:
-                msg.add_success("Local-zone failed to set") 
+                msg.add_error("Local-zone failed to set") 
         else:
             # add all interfaces
             interfaces_form = []
@@ -1668,7 +1681,7 @@ def firewall_zones_add(request):
                         valid = True
                         msg.add_success("Interface added to zone: " +  iface_form)
                     else:
-                        msg.add_success("Interface not added to zone: " +  iface_form + " - "  + v.reason)
+                        msg.add_error("Interface not added to zone: " +  iface_form + " - "  + v.reason)
 
             if valid == True:
                 # if editing remove localzone if set
@@ -1685,18 +1698,18 @@ def firewall_zones_add(request):
                         valid = True
                         msg.add_success("Description defined")
                     else:
-                        msg.add_success("Description failed to set")
+                        msg.add_error("Description failed to set")
 
             if request.POST.get('action', None) != None:
                 zoneaction = request.POST.get('action')
-                zoneaction = zonedescription.strip()
+                zoneaction = zoneaction.strip()
                 if zoneaction in ['drop', 'reject']:
                     v = vapi.set_firewall_zone_defaultaction(hostname_default, zonename, zoneaction)
                     if v.success:   
                         valid = True
                         msg.add_success("Default action defined")       
                     else:
-                        msg.add_success("Default action failed to set")                        
+                        msg.add_error("Default action failed to set")                        
 
 
             msg.add_success("Zone added") 
@@ -1721,16 +1734,15 @@ def firewall_zones_add(request):
     }   
     return HttpResponse(template.render(context, request))
 
-
-
-
-
-
-
 @is_authenticated
 def firewall_zones_edit(request, zonename):
-    msg = vmsg.msg()
+    # validation
+    zonename = zonename.strip()
+    
 
+
+    msg = vmsg.msg()
+    
     # basic methods all views should call
     all_instances       = vyos.instance_getall()
     hostname_default    = vyos.get_hostname_prefered(request)
@@ -1743,6 +1755,30 @@ def firewall_zones_edit(request, zonename):
     get_firewall_zone       = vapi.get_firewall_zone(hostname_default, zonename)
     zoneinfo                = get_firewall_zone.data
 
+    form_changed = False
+    if request.POST.get('form_changed', None) == "1":
+        form_changed = True
+
+    # set interface_alias in format eth0 if has not vif and eth0.vlan if has vlan
+    for iname in interfaces_all_names:
+        if 'vif' in iname:
+            iname['interface_alias'] = "{interface_name}.{vif}".format(interface_name=iname['interface_name'], vif=iname['vif'])
+        else:
+            iname['interface_alias'] = iname['interface_name']
+
+
+    # create a dict
+    interfaces_all_names_dict = {}
+    for iname in interfaces_all_names:
+        if 'vif' in iname:
+            ialias = "{interface_name}.{vif}".format(interface_name=iname['interface_name'], vif=iname['vif'])
+        else:
+            ialias = iname['interface_name']
+
+        interfaces_all_names_dict[ialias] = iname
+
+
+
     if zoneinfo == None:
         msg.add_error("Zone not exists")
         template = loader.get_template('firewall/zones-edit.html')
@@ -1757,93 +1793,198 @@ def firewall_zones_edit(request, zonename):
             'interfaces_all_names':         interfaces_all_names,
             'msg' :                         msg.get_all(),
             "zoneinfo":                     zoneinfo,
+            "zonename":                     zonename,
             "exists":                       False
         }   
         return HttpResponse(template.render(context, request))
 
 
 
-    interfaces_defined          = []
-    interfaces_defined_form     = []
-    interfaces_zone             = {}
-    allzones                    = []
+    interfaces_defined              = []
+    interfaces_defined_form         = []
+    allzones                        = []
+
+    interfaces_zone_alias           = []
+    interfaces_zone_alias_other     = []
+    interfaces_zone                 = []
+    interfaces_zone_other           = []
 
     if get_firewall_zones.success:
         allzones = get_firewall_zones.data
         if 'zone' in allzones:
             for zone in allzones['zone']:
                 if 'interface' in allzones['zone'][zone]:
-                    for zoneinterface in allzones['zone'][zone]['interface']:
+                    if isinstance(allzones['zone'][zone]['interface'], list):
+                        for zoneinterface in allzones['zone'][zone]['interface']:
+                            if zone == zonename:
+                                #print("@@@", zone, zoneinterface)
+                                interfaces_zone_alias.append("interface_" + zoneinterface)
+                                interfaces_zone.append(zoneinterface)
+                            else:
+                                interfaces_zone_alias_other.append("interface_" + zoneinterface)
+                                interfaces_zone_other.append(zoneinterface)
+
+                            interfaces_defined.append(zoneinterface)
+                            interfaces_defined_form.append("interface_" + zoneinterface)
+                    else:
+                        zoneinterface = allzones['zone'][zone]['interface']
+                        if zone == zonename:
+                           # print("@@@", zone, zoneinterface)
+                            interfaces_zone_alias.append("interface_" + zoneinterface)
+                            interfaces_zone.append(zoneinterface)
+                        else:
+                            interfaces_zone_alias_other.append("interface_" + zoneinterface)
+                            interfaces_zone_other.append(zoneinterface)
+  
+
                         interfaces_defined.append(zoneinterface)
                         interfaces_defined_form.append("interface_" + zoneinterface)
-                        interfaces_zone[zoneinterface] = zone
+                            
+    
 
     # local control vars
     valid               = False
     localzone           = False
 
-    if request.POST.get('name', None) != None or len(zonename) > 0:
-        if len(zonename) == 0:
-            zonename = request.POST.get('name')
-            zonename = zonename.strip()
 
-        if request.POST.get('localzone', None) != None:
+    # add all interfaces
+    interfaces_form = []
+    for rv in request.POST:
+        iface_form = None
+        if rv.startswith("interface_"):
+            rvprefixlen = len("interface_")
+            iface_form = rv[rvprefixlen:]
+            interfaces_form.append(iface_form)
+
+    # each interface unset on form we need to delete from zone
+    if form_changed:                
+        for iface in interfaces_all_names:
+            # interface belongs to zone currently
+            if iface["interface_alias"] in interfaces_zone:
+                # interface not marked on form
+                if iface["interface_alias"] not in interfaces_form:
+                    v = vapi.delete_firewall_zone_interface(hostname_default, zonename, iface["interface_alias"])
+                    if v.success:   
+                        valid = True
+                        msg.add_success("Interface {iface} removed from zone.".format(iface=iface["interface_alias"]))
+                        zalias = "interface_" + iface["interface_alias"]
+                        if zalias in interfaces_zone_alias:
+                            interfaces_zone_alias.remove(zalias)
+                    else:
+                        msg.add_error("Interface {iface} not removed from zone: {error}".format(iface=iface["interface_alias"], error=v.reason))
+
+
+    # each interface set on form we need to add to zone
+    for iface in interfaces_form:
+        if iface in interfaces_zone:
+            msg.add_info("Zone add interface {iface} not added since already addded.".format(iface=iface))
+        elif iface in interfaces_zone_other:
+            msg.add_alert("Zone add interface {iface} not added since belongs to other zone.".format(iface=iface))
+        else:
+            v = vapi.set_firewall_zone_interface(hostname_default, zonename, iface)
+            if v.success:   
+                valid = True
+                msg.add_success("Zone add interface {iface} added.".format(iface=iface))
+                zalias = "interface_" + iface
+                interfaces_zone_alias.append(zalias)
+            else:
+                msg.add_success("Zone add interface {iface} not added: {error}.".format(iface=iface, error=v.reason))
+    
+    if request.POST.get('description', None) != None:
+        zonedescription = request.POST.get('description')
+        zonedescription = zonedescription.strip()
+        if 'description' not in zoneinfo or zoneinfo['description'] != zonedescription:
+            if len(zonedescription) > 0:
+                v = vapi.set_firewall_zone_description(hostname_default, zonename, zonedescription)
+                if v.success:   
+                    valid = True
+                    msg.add_success("Description defined")
+                    zoneinfo['description'] = zonedescription
+                else:
+                    msg.add_success("Description failed to set")
+
+    if request.POST.get('action', None) != None:
+        zoneaction = request.POST.get('action')
+        zoneaction = zoneaction.strip()
+        if zoneaction in ['drop', 'reject']:
+            if 'default-action' not in zoneinfo or zoneinfo['default-action'] != zoneaction:
+                v = vapi.set_firewall_zone_defaultaction(hostname_default, zonename, zoneaction)
+                if v.success:   
+                    valid = True
+                    msg.add_success("Default action defined")     
+                    zoneinfo['default-action'] = zoneaction  
+                else:
+                    msg.add_success("Default action failed to set")                        
+
+
+    """if request.POST.get('localzone', None) != None:
             # set local-zone
             v = vapi.set_firewall_zone_localzone(hostname_default, zonename)
             if v.success:   
                 valid = True
                 msg.add_success("Local-zone defined")       
             else:
-                msg.add_success("Local-zone failed to set") 
-        else:
-            # add all interfaces
-            interfaces_form = []
-            for rv in request.POST:
-                iface_form = None
-                if rv.startswith("interface_"):
-                    rvprefixlen = len("interface_")
-                    iface_form = rv[rvprefixlen:]
-                    interfaces_form.append(iface_form)
-
-                    v = vapi.set_firewall_zone_interface(hostname_default, zonename, iface_form)
-                    if v.success:   
-                        valid = True
-                        msg.add_success("Interface added to zone: " +  iface_form)
-                    else:
-                        msg.add_success("Interface not added to zone: " +  iface_form + " - "  + v.reason)
-
-            if valid == True:
-                # if editing remove localzone if set
-                pass
+                msg.add_success("Local-zone failed to set")"""
 
+    zoneaction = None
+    if 'default-action' in zoneinfo:
+        zoneaction = zoneinfo['default-action']
 
-        if valid == True:
-            if request.POST.get('description', None) != None:
-                zonedescription = request.POST.get('description')
-                zonedescription = zonedescription.strip()
-                if len(zonedescription) > 0:
-                    v = vapi.set_firewall_zone_description(hostname_default, zonename, zonedescription)
-                    if v.success:   
-                        valid = True
-                        msg.add_success("Description defined")
-                    else:
-                        msg.add_success("Description failed to set")
+    template = loader.get_template('firewall/zones-edit.html')
+    context = { 
+        #'interfaces': interfaces,
+        'instances':                        all_instances,
+        'hostname_default':                 hostname_default,
+        'username':                         request.user,
+        'is_superuser':                     is_superuser,
+        'interfaces':                       interfaces,
+        'interfaces_pretty':                pprint.pformat(interfaces, indent=4, width=120),
+        'interfaces_all_names_pretty':      pprint.pformat(interfaces_all_names, indent=4, width=120),
+        'interfaces_all_names':             interfaces_all_names,
+        'msg' :                             msg.get_all(),
+        'allzones':                         allzones,
+        'interfaces_defined':               interfaces_defined,
+        'interfaces_defined_form':          interfaces_defined_form,
+        'interfaces_zone_alias':            interfaces_zone_alias,
+        'interfaces_zone_alias_other':      interfaces_zone_alias_other,
+        "zoneinfo":                         zoneinfo,
+        "allzones_pretty":                  pprint.pformat(allzones, indent=4, width=120),
+        "zonename":                         zonename,
+        "exists":                           True,
+        'interfaces_all_names_dict':        interfaces_all_names_dict,
+        'interfaces_all_names_dict_pretty': pprint.pformat(interfaces_all_names_dict, indent=4, width=120),
+        'zoneaction':                       zoneaction,
+    }   
+    return HttpResponse(template.render(context, request))
 
-            if request.POST.get('action', None) != None:
-                zoneaction = request.POST.get('action')
-                zoneaction = zonedescription.strip()
-                if zoneaction in ['drop', 'reject']:
-                    v = vapi.set_firewall_zone_defaultaction(hostname_default, zonename, zoneaction)
-                    if v.success:   
-                        valid = True
-                        msg.add_success("Default action defined")       
-                    else:
-                        msg.add_success("Default action failed to set")                        
+@is_authenticated
+def firewall_zones_remove(request, zonename):
+    # validation
+    zonename = zonename.strip()
+    
+    msg = vmsg.msg()
+    
+    # basic methods all views should call
+    all_instances       = vyos.instance_getall()
+    hostname_default    = vyos.get_hostname_prefered(request)
+    is_superuser        = perms.get_is_superuser(request.user)
 
+    # local methods to prepare env
+    interfaces              = vyos.get_interfaces(hostname_default)
+    interfaces_all_names    = vyos.get_interfaces_all_names(hostname_default)
+    get_firewall_zone       = vapi.get_firewall_zone(hostname_default, zonename)
+    zoneinfo                = get_firewall_zone.data
 
-            msg.add_success("Zone added") 
+    if zoneinfo == None:
+        msg.add_error("Zone not exists")
+    else:
+        v = vapi.delete_firewall_zone(hostname_default, zonename)
+        if v.success:   
+            msg.add_success("Zone {zone} removed".format(zone=zonename))
+        else:
+            msg.add_error("Zone {zone} not removed: {error}".format(zone=zonename, error=v.reason))
 
-    template = loader.get_template('firewall/zones-edit.html')
+    template = loader.get_template('firewall/zones-remove.html')
     context = { 
         #'interfaces': interfaces,
         'instances':                    all_instances,
@@ -1851,20 +1992,159 @@ def firewall_zones_edit(request, zonename):
         'username':                     request.user,
         'is_superuser':                 is_superuser,
         'interfaces':                   interfaces,
-        'interfaces_pretty':            pprint.pformat(interfaces, indent=4, width=120),
         'interfaces_all_names_pretty':  pprint.pformat(interfaces_all_names, indent=4, width=120),
         'interfaces_all_names':         interfaces_all_names,
         'msg' :                         msg.get_all(),
-        'allzones':                     allzones,
-        'interfaces_defined':           interfaces_defined,
-        'interfaces_defined_form':      interfaces_defined_form,
-        'interfaces_zone':              interfaces_zone,
-        'form_added':                   valid,
         "zoneinfo":                     zoneinfo,
         "zonename":                     zonename,
-        "exists":                       True,
+    }   
+    return HttpResponse(template.render(context, request))
 
+@is_authenticated
+def firewall_zones_addrule(request):
+    msg = vmsg.msg()
+    
+    # basic methods all views should call
+    all_instances       = vyos.instance_getall()
+    hostname_default    = vyos.get_hostname_prefered(request)
+    is_superuser        = perms.get_is_superuser(request.user)
+
+    # local methods to prepare env
+    interfaces              = vyos.get_interfaces(hostname_default)
+    interfaces_all_names    = vyos.get_interfaces_all_names(hostname_default)
+    get_firewall_zones      = vapi.get_firewall_zones(hostname_default) 
+
+    zones = []
+    if get_firewall_zones.success:
+        allzones = get_firewall_zones.data
+        if 'zone' in allzones:
+            for zone in allzones['zone']:
+                zones.append(zone)                        
+
+    firewalls = []
+    firewall_all = vyos.get_firewall_all(hostname_default)
+    if firewall_all == False:
+        return redirect('firewall:firewall-create')
+    if 'name' in firewall_all:
+        for firewall in firewall_all['name']:
+            firewalls.append(firewall)
+
+    reverse = False
+    if request.POST.get('reverse', None) == "1":
+        reverse = True
+
+    dstzone = None
+    srczone = None
+    firewallrule = None
+
+    if request.POST.get('dstzone', None) != None:
+        dstzone = request.POST.get('dstzone').strip()
+
+    if request.POST.get('srczone', None) != None:
+        srczone = request.POST.get('srczone').strip()
+
+    if request.POST.get('firewall', None) != None:
+        firewallrule = request.POST.get('firewall').strip()
+
+    if dstzone != None and srczone != None and firewallrule != None:
+        v = vapi.set_interface_firewall_zone_addrule(hostname_default, dstzone, srczone, firewallrule)
+        if v.success:   
+            msg.add_success("Zone ruleset zone {dst} from {src} firewall {firewall} added".format(
+                dst=dstzone,
+                src=srczone,
+                firewall=firewallrule
+            ))
+        else:
+            msg.add_error("Zone ruleset {dst} from {src} firewall {firewall} not added: {reason}".format(
+                dst=dstzone,
+                src=srczone,
+                firewall=firewallrule
+            ))
+
+        if reverse == True:
+            v = vapi.set_interface_firewall_zone_addrule(hostname_default, srczone, dstzone, firewallrule)
+            if v.success:   
+                msg.add_success("Zone reverse ruleset {dst} from {src} firewall {firewall} added".format(
+                    dst=srczone,
+                    src=dstzone,
+                    firewall=firewallrule
+                ))
+            else:
+                msg.add_error("Zone reverse ruleset {dst} from {src} firewall {firewall} not added: {reason}".format(  
+                    dst=srczone,
+                    src=dstzone,
+                    firewall=firewallrule
+                ))
+
+
+
+ 
+    template = loader.get_template('firewall/zones-addrule.html')
+    context = { 
+        #'interfaces': interfaces,
+        'instances':                    all_instances,
+        'hostname_default':             hostname_default,
+        'username':                     request.user,
+        'is_superuser':                 is_superuser,
+        'interfaces':                   interfaces,
+        'interfaces_all_names_pretty':  pprint.pformat(interfaces_all_names, indent=4, width=120),
+        'interfaces_all_names':         interfaces_all_names,
+        'msg' :                         msg.get_all(),
+        'zones' :                       zones,
+        'firewalls' :                   firewalls
     }   
     return HttpResponse(template.render(context, request))
 
 
+
+@is_authenticated
+def firewall_zones_removerule(request, dstzone, srczone, firewall):
+    # validation
+    dstzone = dstzone.strip()
+    srczone = srczone.strip()
+    firewall = firewall.strip()
+    
+    msg = vmsg.msg()
+    
+    # basic methods all views should call
+    all_instances       = vyos.instance_getall()
+    hostname_default    = vyos.get_hostname_prefered(request)
+    is_superuser        = perms.get_is_superuser(request.user)
+
+    # local methods to prepare env
+    interfaces              = vyos.get_interfaces(hostname_default)
+    interfaces_all_names    = vyos.get_interfaces_all_names(hostname_default)
+    get_firewall_zonedst    = vapi.get_firewall_zone(hostname_default, dstzone)
+    zoneinfodst             = get_firewall_zonedst.data
+    get_firewall_zonesrc    = vapi.get_firewall_zone(hostname_default, srczone)
+    zoneinfosrc             = get_firewall_zonesrc.data    
+
+    if zoneinfodst == None or zoneinfosrc == None:
+        msg.add_error("Zone not exists")
+    else:
+        v = vapi.delete_interface_firewall_zone_rule(hostname_default, dstzone, srczone)
+        if v.success:   
+            msg.add_success("Zone ruleset {dst} from {src} removed".format(  
+                dst=dstzone,
+                src=srczone,
+            ))            
+        else:
+            msg.add_error("Zone ruleset {dst} from {src} not removed: {reason}".format(  
+                dst=dstzone,
+                src=srczone,
+                reason=v.reason
+            ))
+
+    template = loader.get_template('firewall/zones-removerule.html')
+    context = { 
+        #'interfaces': interfaces,
+        'instances':                    all_instances,
+        'hostname_default':             hostname_default,
+        'username':                     request.user,
+        'is_superuser':                 is_superuser,
+        'interfaces':                   interfaces,
+        'interfaces_all_names_pretty':  pprint.pformat(interfaces_all_names, indent=4, width=120),
+        'interfaces_all_names':         interfaces_all_names,
+        'msg' :                         msg.get_all(),
+    }   
+    return HttpResponse(template.render(context, request))

+ 52 - 0
vycontrol/vycontrol_vyos_api.py

@@ -415,6 +415,27 @@ def set_firewall_zone_interface(hostname, zonename, interface):
     )
     return v    
 
+def delete_firewall_zone_interface(hostname, zonename, interface):
+    v = vapilib.api (
+        hostname=   hostname,
+        api =       "post",
+        op =        "delete",
+        cmd =       ["zone-policy", "zone", zonename, "interface", interface],
+        description = "delete_firewall_zone_interface",
+    )
+    return v   
+
+def delete_firewall_zone(hostname, zonename):
+    v = vapilib.api (
+        hostname=   hostname,
+        api =       "post",
+        op =        "delete",
+        cmd =       ["zone-policy", "zone", zonename],
+        description = "delete_firewall_zone",
+    )
+    return v       
+
+
 def get_firewall_zones(hostname):
     v = vapilib.api (
         hostname=   hostname,
@@ -479,3 +500,34 @@ def delete_interface_firewall_ipv4(hostname, interface_type, interface_name, dir
 
 
 
+def set_interface_firewall_zone_addrule(hostname, dstzone, srczone, firewall):
+    v = vapilib.api (
+        hostname=   hostname,
+        api =       "post",
+        op =        "set",
+        cmd =       ["zone-policy", "zone", dstzone, "from", srczone, "firewall", "name", firewall],
+        description = "set_interface_firewall_zone_addrule",
+    )
+    return v  
+
+
+def delete_interface_firewall_zone_rule(hostname, dstzone, srczone):
+    v = vapilib.api (
+        hostname=   hostname,
+        api =       "post",
+        op =        "delete",
+        cmd =       ["zone-policy", "zone", dstzone, "from", srczone],
+        description = "delete_interface_firewall_zone_rule",
+    )
+    return v  
+
+
+def delete_interface_firewall_zone_rule_firewall(hostname, dstzone, srczone, firewall):
+    v = vapilib.api (
+        hostname=   hostname,
+        api =       "post",
+        op =        "delete",
+        cmd =       ["zone-policy", "zone", dstzone, "from", srczone, "firewall", "name", firewall],
+        description = "delete_interface_firewall_zone_rule",
+    )
+    return v