浏览代码

Merge pull request #94 from vycontrol/20.05.02

released 20.05.02.1000
Roberto Bertó 5 年之前
父节点
当前提交
fe91bcd5bc

+ 2 - 3
vycontrol/config/views.py

@@ -20,10 +20,9 @@ from django.template.defaultfilters import register
 from perms import is_authenticated
 from perms import is_authenticated
 import perms
 import perms
 
 
+from filters.vycontrol_filters import get_item
+
 
 
-@register.filter
-def get_item(dictionary, key):
-    return dictionary.get(key)
 
 
 @is_authenticated
 @is_authenticated
 def index(request):
 def index(request):

+ 20 - 1
vycontrol/filters/vycontrol_filters.py

@@ -9,4 +9,23 @@ def routepack(value):
 @register.filter
 @register.filter
 def routeunpack(value): 
 def routeunpack(value): 
     """UnpPack a route into a string"""
     """UnpPack a route into a string"""
-    return str(value).replace("!","/")
+    return str(value).replace("!","/")
+
+@register.filter
+def get_item(dictionary, key):
+    return dictionary.get(key)
+
+@register.filter
+def get_item_port(dictionary, key):
+    d = dictionary.get(key)    
+    # n = port
+    # p = protocol
+    # d = description
+    return d['n']
+
+
+@register.filter
+def get_item_network(dictionary, key):
+    d = dictionary.get(key)    
+    return d['network']
+

+ 66 - 38
vycontrol/firewall/templates/firewall/addressgroup-add.html

@@ -14,73 +14,101 @@
     <a href="{% url 'firewall:firewall-list' %}">Firewall List</a> | 
     <a href="{% url 'firewall:firewall-list' %}">Firewall List</a> | 
     <a href="{% url 'firewall:firewall-create' %}">Create new firewall</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-addressgroup-list' %}">Address Group</a> |
-    <a href="{% url 'firewall:firewall-networkgroup-list' %}">Network Group</a>
+    <a href="{% url 'firewall:firewall-addressgroup-list' %}">Network Group</a> | 
+    <a href="{% url 'firewall:firewall-portgroup-list' %}">Port Group</a>
 </p>
 </p>
 <p class="submenu2"></p>
 <p class="submenu2"></p>
 
 
 
 
-<form action="{% url 'firewall:firewall-addressgroup-add' %}" method="post">
+<form action="{% url 'firewall:firewall-addressgroup-add' %}" method="post" id="formng">
     {% csrf_token %}
     {% csrf_token %}
 
 
 
 
     <p>
     <p>
-        <label for="name">group name:</label><br>
-        <input type="input" name="name" id="name" value="" size="30" />
+    <label for="name">group name:</label><br>
+    <input type="input" name="name" id="name" value="" size="30" />
     </p>
     </p>
 
 
-
     <p>
     <p>
         <label for="name">description:</label><br>
         <label for="name">description:</label><br>
         <input type="input" name="description" id="description" value="" size="100" />
         <input type="input" name="description" id="description" value="" size="100" />
     </p>
     </p>
-
+    
     <p>
     <p>
-    address type: <br>
-    <input type="radio" name="addresstype" value="single" id="addresstype_single" class="addresstype" /> <label for="addresstype">single address</label>
-    <input type="radio" name="addresstype" value="range" id="addresstype_range" class="addresstype"/> <label for="addresstype">range address</label>
+        <label for="network">addresses (IP or interval):</label><br>
+        <input type="input" name="network" id="network" value=""/> (eg 192.168.0.1 or 192.168.0.1-192.168.0.10) 
+        <input type="button" value="add" id="addressgroup_add">
     </p>
     </p>
-    
 
 
+    <p>
+        <label for="addressgroup">addresses (click to remove)</label><br>
+        <select name="addressgroup" id="addressgroup" size="10" style="width: 200px;">
+        </select>
 
 
-    <div id="addresstype_single_block" style="display: none">
-        <table width="100%">
-            <tr>
-                <th width="25%">ip address:</td><td><input type="input" name="address" value=""/> </th>
-            </tr>
-        </table>
-    </div>
 
 
-    <div id="addresstype_range_block" style="display: none">
-        <table width="100%">
-            <tr>
-                <th width="25%">ip block address start:</td><td><input type="input" name="address-start" value=""/> (eg 10.10.10.1)</th>
-            </tr>
-            <tr>
-                <th width="25%">ip block address end:</td><td><input type="input" name="address-end" value=""/>  (eg 10.10.10.20)</th>
-            </tr>
-        </table>
-    </div>
+        <input type="hidden" name="addressgroup_json" id="addressgroup_json" value="" >
+    </p>
 
 
 
 
     <input type="submit" value="Add Group">
     <input type="submit" value="Add Group">
 </form>
 </form>
 
 
+
 <script>
 <script>
-$(document).ready(function () {                            
-    $(".addresstype").change(function () {
-        if ($("#addresstype_single").is(":checked")) {
-            $('#addresstype_single_block').show();
-            $('#addresstype_range_block').hide();
+$(document).ready(function () {
+    $("#addressgroup_add").click(function () {
+        network = $("#network").val();
+
+        if (network !=  "") {
+            if ($("#addressgroup option[value='" + network + "']").length == 0) {
+                $('#addressgroup').append($('<option>', {
+                    value: network,
+                    text: network
+                }));
+            }
         }
         }
-        else if ($("#addresstype_range").is(":checked")) {
-            $('#addresstype_single_block').hide();
-            $('#addresstype_range_block').show();
+    });
+
+
+    $('#addressgroup').click(function() {
+            $(this).find('option:selected').remove();
+    });
+
+    // form basic validations
+    $("#formng").submit(function(e){
+        size = $("#addressgroup option").length
+        if (size < 1) {
+            alert('Minimum networks is 1');
+            e.preventDefault();
+            return false;
         }
         }
-    });        
-});
-</script>
+        
+        groupname = $("#name").val()
+        if (groupname.length > 31) {
+            alert('Maximum group name 31 characters or less');
+            e.preventDefault();
+            return false;
+        }
+
+
+
+        var groupa = []
+        $("#addressgroup option").each(function() {
+            groupa.push($(this).val());
+        });
+
+        var groupa_json = JSON.stringify(groupa);
+        $("#addressgroup_json").val(groupa_json);
 
 
+        console.log(groupa_json)
+    });
 
 
+})
+
+
+
+
+</script>
 
 
 
 
 
 

+ 128 - 0
vycontrol/firewall/templates/firewall/addressgroup-desc.html

@@ -0,0 +1,128 @@
+{% extends "base.html" %}
+
+{% block header_title %}Edit Addressgroup{% endblock %}
+{% block section_title %}Edit Addressgroup{% endblock %}
+{% block username %}{{ username }}{% endblock %}
+
+{% block debug %}
+{{ firewall_all }}
+{{ firewall_networkgroup }}
+{% endblock %}
+
+
+{% block content %}
+
+
+<script type="text/javascript">
+    var networkgroup_data = JSON.parse('{{networks_json|safe}}');
+    console.log(networkgroup_data);
+</script>
+
+<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>
+</p>
+<p class="submenu2">
+    <a href="{% url 'firewall:firewall-addressgroup-add' %}">Add network Group</a>
+</p>
+
+
+
+
+
+<form action="{% url 'firewall:firewall-addressgroup-desc' groupname %}" method="post" id="formng">
+    {% csrf_token %}
+
+    <p>
+        <label for="name">description:</label><br>
+        <input type="input" name="description" id="description" value="{{ groupinfo.description }}" size="100" />
+    </p>
+    
+    <p>
+        <label for="network">network (CIDR notation):</label><br>
+        <input type="input" name="network" id="network" value=""/> (eg 10.10.10.0/24) 
+        <input type="button" value="add" id="networkgroup_add">
+    </p>
+
+    <p>
+        <label for="networkgroup">networks (click to remove)</label><br>
+        <select name="networkgroup" id="networkgroup" size="10" style="width: 200px;">
+        </select>
+
+
+        <input type="hidden" name="networkgroup_json" id="networkgroup_json" value="" >
+    </p>
+
+
+    <input type="submit" value="Edit Group">
+</form>
+
+
+<script>
+$(document).ready(function () {
+
+    for (network in networkgroup_data) {
+        $('#networkgroup').append($('<option>', {
+            value: networkgroup_data[network],
+            text: networkgroup_data[network]
+        }));
+    }
+
+    $("#networkgroup_add").click(function () {
+        network = $("#network").val();
+
+        if (network !=  "") {
+            if ($("#networkgroup option[value='" + network + "']").length == 0) {
+                $('#networkgroup').append($('<option>', {
+                    value: network,
+                    text: network
+                }));
+            }
+        }
+    });
+
+
+    $('#networkgroup').click(function() {
+            $(this).find('option:selected').remove();
+    });
+
+    // form basic validations
+    $("#formng").submit(function(e){
+        size = $("#networkgroup option").length
+        if (size < 1) {
+            alert('Minimum networks is 1');
+            e.preventDefault();
+            return false;
+        }
+        
+        var groupa = []
+        $("#networkgroup option").each(function() {
+            groupa.push($(this).val());
+        });
+
+        var groupa_json = JSON.stringify(groupa);
+        $("#networkgroup_json").val(groupa_json);
+
+        console.log(groupa_json)
+        //e.preventDefault();
+        //return false;
+
+    });
+
+})
+
+
+
+
+</script>
+
+    
+
+
+{% endblock %}
+
+
+

+ 13 - 4
vycontrol/firewall/templates/firewall/addressgroup-list.html

@@ -13,7 +13,8 @@
 <p class="submenu1">
 <p class="submenu1">
     <a href="{% url 'firewall:firewall-list' %}">Firewall List</a> | 
     <a href="{% url 'firewall:firewall-list' %}">Firewall List</a> | 
     <a href="{% url 'firewall:firewall-create' %}">Create new firewall</a> | 
     <a href="{% url 'firewall:firewall-create' %}">Create new firewall</a> | 
-    <a href="{% url 'firewall:firewall-networkgroup-list' %}">Network Group</a>
+    <a href="{% url 'firewall:firewall-networkgroup-list' %}">Network Group</a> | 
+    <a href="{% url 'firewall:firewall-portgroup-list' %}">Port Group</a>
 </p>
 </p>
 <p class="submenu2">
 <p class="submenu2">
     <a href="{% url 'firewall:firewall-addressgroup-add' %}">Add Address Group</a>
     <a href="{% url 'firewall:firewall-addressgroup-add' %}">Add Address Group</a>
@@ -22,14 +23,22 @@
 
 
 {% if firewall_addressgroup %}
 {% if firewall_addressgroup %}
     <table border="1" width="100%">
     <table border="1" width="100%">
-        <tr><th width="25%">name</th><th width="25%">address</th><th width="50%">description</th></tr>
+        <tr>
+            <th width="25%">name</th>
+            <th width="30%">description</th>
+            <th width="25%">actions</th>
+        </tr>
 
 
     {% for key, value in firewall_addressgroup.items %}       
     {% for key, value in firewall_addressgroup.items %}       
         {% for ifkey, ifvalue in value.items %}
         {% for ifkey, ifvalue in value.items %}
             <tr>
             <tr>
-                <td>{{ ifkey }}</a></td>
-                <td>{{ ifvalue.address }}</td>
+                <td><a href="{% url 'firewall:firewall-addressgroup-desc' ifkey %}">{{ ifkey }}</a></td>
+                {% comment %}<td>{{ ifvalue.address }}</td>{% endcomment %}
                 <td>{{ ifvalue.description }}</td>
                 <td>{{ ifvalue.description }}</td>
+                <td>
+                    <a href="{% url 'firewall:firewall-addressgroup-desc' ifkey %}">Edit</a> | 
+                    <a href="{% url 'firewall:firewall-addressgroup-del' ifkey %}">Remove</a>
+                </td>
             </tr>
             </tr>
         {% endfor %}
         {% endfor %}
         
         

+ 675 - 31
vycontrol/firewall/templates/firewall/addrule.html

@@ -5,17 +5,44 @@
 {% block username %}{{ username }}{% endblock %}
 {% block username %}{{ username }}{% endblock %}
 
 
 {% block debug %}
 {% block debug %}
-{{ firewall }}
+
 {{ firewall_name }}
 {{ firewall_name }}
+
+{{ services }}
+
+{{ services_common }}
+
+{{ firewall_networkgroup }}
+
+{{ firewall_addressgroup }}
+
+
 {% endblock %}
 {% endblock %}
 
 
 {% block content %}
 {% block content %}
 
 
+{% comment %}
+<script type="text/javascript">
+    var firewall_networkgroup_data = '{{firewall_networkgroup_js|safe}}';
+    console.log(firewall_networkgroup_data);
+
+    var firewall_addressgroup_data = '{{firewall_addressgroup_js|safe}}';
+    console.log(firewall_addressgroup_data);    
+
+    var netservices_js = '{{netservices_js|safe}}';
+    console.log(netservices_js);    
+
+</script>
+{% endcomment %}
+
 
 
 <p class="submenu1">
 <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-create' %}">Create new firewall</a> | 
     <a href="{% url 'firewall:firewall-addressgroup-list' %}">Address Group</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-networkgroup-list' %}">Network Group</a> | 
+    <a href="{% url 'firewall:firewall-portgroup-list' %}">Port Group</a>
 </p>
 </p>
 <p class="submenu2">
 <p class="submenu2">
     
     
@@ -23,43 +50,660 @@
 
 
 
 
 
 
-<form action="{% url 'firewall:addrule' firewall_name %}" method="post">
+<form action="{% url 'firewall:addrule' firewall_name %}" method="post" id="form_addrule">
     {% csrf_token %}
     {% csrf_token %}
     
     
-    <p>
-        <label for="alias">rule number</label><br>
-        <input type="text" name="rulenumber" id="rulenumber" value="{{ rulenumber }}" size="5">
-    </p>
-    
-    <p>
-        <label for="hostname">action</label><br>
-        <input type="radio" name="action" id="action" value="accept"> accept
-        <input type="radio" name="action" id="action" value="drop"> drop
-        <input type="radio" name="action" id="action" value="reject"> reject        
-    </p>
-
-    <p>
-        <label for="hostname">protocol</label><br>
-        <input type="radio" name="protocol" id="protocol" value="tcp"> tcp
-        <input type="radio" name="protocol" id="protocol" value="udp"> udp
-    </p>   
-    
-    <p>
-        <label for="alias">destination port</label><br>
-        <input type="text" name="destinationport" id="destinationport" value="{{ destinationport }}" size="5">
-    </p>
-    
-    <p>
-        <label for="alias">source port</label><br>
-        <input type="text" name="sourceport" id="sourceport" value="{{ sourceport }}" size="5">
-    </p>    
+
+    <h3>Rule Config</h3>
+    <div class="container">
+        <div class="row">
+            <div class="col">
+                <p>
+                    <label for="alias">rule number</label><br>
+                    <input type="text" name="rulenumber" id="rulenumber" value="{{ rulenumber }}" size="5">
+                </p>
+            </div>
+
+            <div class="col">
+                <p>
+                    <label for="status">status</label><br>
+                    <input type="radio" name="status" id="status" value="enabled" checked="checked"> enabled
+                    <input type="radio" name="status" id="status" value="disabled"> disabled
+                </p>
+            </div>         
+
+            <div class="col">
+                <p>
+                    <label for="action">action</label><br>
+                    <input type="radio" class="fwaction" name="ruleaction" id="action" value="accept"> accept
+                    <input type="radio" class="fwaction" name="ruleaction" id="action" value="drop"> drop
+                    <input type="radio" class="fwaction" name="ruleaction" id="action" value="reject"> reject        
+                </p>
+            </div>
+        </div>
+
+        <div class="row">
+            <div class="col">
+                <p>
+                    <label for="alias">description</label><br>
+                    <input type="text" name="description" id="description" value="{{ description }}" size="60">
+                </p>
+            </div>
+
+
+        </div>       
+    </div>
+
+
+    <h3 class="matching_criteria"><input type="checkbox" name="criteria_protocol" value="1" id="criteria_protocol"> <label for="criteria_protocol" class="label_for_h3">Matching criteria - protocol</label></h3>
+    <div class="container" id="criteria_protocol_block" style="display: none">
+
+        <div class="row">
+
+            <div class="col">
+                <p>
+                    <input type="radio" class="protocol_criteria" name="protocol_criteria" id="protocol_criteria_all" value="all"> all protocols<br>
+                    <input type="radio" class="protocol_criteria" name="protocol_criteria" id="protocol_criteria_tcp" value="tcp"> tcp<br>
+                    <input type="radio" class="protocol_criteria" name="protocol_criteria" id="protocol_criteria_udp" value="udp"> udp<br>
+                    <input type="radio" class="protocol_criteria" name="protocol_criteria" id="protocol_criteria_tcp_udp" value="tcp_udp"> tcp and udp<br>
+                    <input type="radio" class="protocol_criteria" name="protocol_criteria" id="protocol_criteria_icmp" value="icmp"> icmp<br>
+                    <input type="radio" class="protocol_criteria" name="protocol_criteria" id="protocol_criteria_other" value="other"> other  
+                </p>
+
+
+            </div>
+
+            <div class="col">
+                
+
+                <p id="protocol_custom_block" style="display: none">
+                    <label for="protocol_custom">other protocol</label><br>
+                    <input type="text" name="protocol_custom" id="protocol_custom" value="{{ protocol_custom }}" size="5"> 
+                </p>                     
+                    
+                {% comment %}
+                <!-- require https://phabricator.vyos.net/T2451 be fixed -->
+                <p>
+                    <input type="checkbox" name="protocol_negate" id="protocol_negate" value="1">
+                    <label for="protocol_negate">negate </label>
+                </p>
+                {% endcomment %}
+            </div>
+        </div>
+    </div>
+
+    <h3  class="matching_criteria" id="criteria_port_block_header" style="display: none"><input type="checkbox" name="criteria_port" value="1" id="criteria_port"> <label for="criteria_port" class="label_for_h3">Matching criteria - port</label></h3>
+    <div class="container" id="criteria_port_block" style="display: none">
+        <div class="row">  
+            <div class="col">
+
+                
+                <p>
+                    <label for="destinationport_common">common destinations ports to add</label><br>
+                    <select name="destinationport_common" id="destinationport_common" size="1">
+                        <option value="">select one</option>
+                        {% for p in services_common %}
+                        <option value="{{ services|get_item_port:p }}">{{ p }} - {{ services|get_item_port:p }} </option>
+                        {% endfor %}
+                    </select>
+
+                    {% comment %}
+                    <input type="checkbox" name="destinationport_common_negate" id="destinationport_common_negate" value="1">
+                    <label for="destinationport_common_negate">negate </label>
+                    {% endcomment %}
+
+                    <input type="button" name="destinationport_common_add" id="destinationport_common_add" value="add" />
+                </p>
+
+
+                <p>
+                    <label for="destinationport_custom">add custom destination ports (use single 100 or range 100-200)</label><br>
+                    <input type="text" name="destinationport_custom" id="destinationport_custom" value="{{ destinationport_custom }}" size="14"> 
+                    
+                    {% comment %}
+                    <input type="checkbox" name="destinationport_custom_negate" id="destinationport_custom_negate" value="1"> 
+                    <label for="destinationport_custom_negate">negate </label>
+                    {% endcomment %}
+
+                    <input type="button" name="destinationport_custom_add" id="destinationport_custom_add" value="add" />
+                </p>                     
+                
+                <p>
+                    <label for="destinationport">destination ports filtered (click to remove)</label><br>
+                    <select name="destinationport" id="destinationport" size="10" style="width: 200px;">
+                    </select>
+
+
+                    <input type="hidden" name="destinationport_json" id="destinationport_json" value="" >
+                </p>
+                
+
+            </div>
+          
+            <div class="col">
+                <p>
+                    <label for="sourceport_common">common source ports to add</label><br>
+                    <select name="sourceport_common" id="sourceport_common" size="1">
+                        <option value="">select one</option>
+                        {% for p in services_common %}
+                        <option value="{{ services|get_item_port:p }}">{{ p }} - {{ services|get_item_port:p }}</option>
+                        {% endfor %}
+                    </select>
+
+                    <input type="checkbox" name="sourceport_common_negate" id="sourceport_common_negate" value="1">
+                    <label for="sourceport_common_negate">negate </label>
+                    <input type="button" name="sourceport_common_add" id="sourceport_common_add" value="add" />
+                </p>   
+
+                <p>
+                    <label for="sourceport_custom">add custom destination ports (use single 100 or range 100-200)</label><br>
+                    <input type="text" name="sourceport_custom" id="sourceport_custom" value="{{ destinationport_custom }}" size="14"> 
+                    <input type="checkbox" name="sourceport_custom_negate" id="sourceport_custom_negate" value="1"> 
+                    <label for="sourceport_custom_negate">negate </label>
+                    <input type="button" name="sourceport_custom_add" id="sourceport_custom_add" value="add" />
+                </p>       
+               
+                <p>
+                    <label for="sourceport">source ports filtered (click to remove)</label><br>
+                    <select name="sourceport" size="10" style="width: 200px;" id="sourceport">
+                    </select>
+
+                    <input type="hidden" name="sourceport_json" id="sourceport_json" value="" >
+
+
+                </p>
+
+
+            </div>
+        </div>
+
+    </div>
+
+    <h3 class="matching_criteria" id="criteria_tcpflags_header" style="display: none"><input type="checkbox" id="criteria_tcpflags" value="1" name="criteria_tcpflags"> <label for="criteria_tcpflags" class="label_for_h3">Matching criteria - TCP Flags</label></h3>    
+    <div class="container" id="criteria_tcpflags_block" style="display: none">
+        <div class="row">
+            <div class="col">
+                <table width="100%">
+                    <tr>
+                        <th>Allow flag</th>
+                        <th>Negate flag</th>
+                    </tr>
+                    <tr>
+                        <td><input type="checkbox" name="tcpflags_syn" id="tcpflags_syn" value="1"> SYN</td>
+                        <td><input type="checkbox" name="tcpflags_isyn" id="tcpflags_isyn" value="1"> !SYN</td>
+                    </tr>
+                    <tr>
+                        <td><input type="checkbox" name="tcpflags_ack" id="tcpflags_ack" value="1"> ACK</td>
+                        <td><input type="checkbox" name="tcpflags_iack" id="tcpflags_iack" value="1"> !ACK</td>
+                    </tr>
+                    <tr>
+                        <td><input type="checkbox" name="tcpflags_fin" id="tcpflags_fin" value="1"> FIN</td>
+                        <td><input type="checkbox" name="tcpflags_ifin" id="tcpflags_ifin" value="1"> !FIN</td>
+                    </tr>
+                    <tr>
+                        <td><input type="checkbox" name="tcpflags_rst" id="tcpflags_rst" value="1"> RST</td>
+                        <td><input type="checkbox" name="tcpflags_irst" id="tcpflags_irst" value="1"> !RST</td>
+                    </tr>
+                    <tr>
+                        <td><input type="checkbox" name="tcpflags_urg" id="tcpflags_urg" value="1"> URG</td>
+                        <td><input type="checkbox" name="tcpflags_iurg" id="tcpflags_iurg" value="1"> !URG</td>
+                    </tr>
+                    <tr>
+                        <td><input type="checkbox" name="tcpflags_psh" id="tcpflags_psh" value="1"> PSH</td>
+                        <td><input type="checkbox" name="tcpflags_ipsh" id="tcpflags_ipsh" value="1"> !PSH</td>
+                    </tr>
+                    <tr>
+                        <td><input type="checkbox" name="tcpflags_all" id="tcpflags_all" value="1"> ALL</td>
+                        <td><input type="checkbox" name="tcpflags_iall" id="tcpflags_iall" value="1"> !ALL</td>
+                    </tr>                        
+                </table>
+            </div>
+
+        </div>
+    </div>
+
+    <h3 class="matching_criteria"><input type="checkbox" id="criteria_address" value="1" name="criteria_address"> <label for="criteria_address" class="label_for_h3">Matching criteria - address</label></h3>
+    <div class="container" id="criteria_address_block" style="display: none">
+
+        <div class="row">
+            <div class="col">
+                <p>
+                    <label for="sdaddress_source">source address</label><br>
+                    <input type="text" name="sdaddress_source" id="sdaddress_source" value="" size="30">
+                </p>
+
+                <p>
+                    <input type="checkbox" name="sdaddress_source_negate" id="sdaddress_source_negate" value="1"> <label for="sdaddress_source_negate">negate source address</label>
+                </p>         
+            </div>
+
+            <div class="col">
+                <p>
+                    <label for="sdaddress_destination">destination address</label><br>
+                    <input type="text" name="sdaddress_destination" id="sdaddress_destination" value="" size="30">
+                </p>
+
+                <p>
+                    <input type="checkbox" name="sdaddress_destination_negate" id="sdaddress_destination_negate" value="1"> <label for="sdaddress_destination_negate">negate destination address</label>
+                </p>         
+             </div>
+        </div>
+
+
+        <div class="row">
+            <div class="col">    
+                <h4>Valid address examples</h4>
+            </div>
+        </div>
+
+        <div class="row">
+            <div class="col">
+                <dl>
+                    <dt>address</dt>
+                    <dd>192.0.2.1</dd>
+                    <dt>address range</dt>
+                    <dd>192.0.2.0-192.0.2.10</dd>
+                    <dt>CIDR</dt>
+                    <dd>192.0.2.0/24</dd>   
+                </dl>
+            </div>
+        </div>
+    </div>
     
     
+    <h3 class="matching_criteria"><input type="checkbox" id="criteria_addressgroup" value="1" name="criteria_addressgroup"> <label for="criteria_addressgroup" class="label_for_h3">Matching criteria - address-group</label></h3>    
+    <div class="container" id="criteria_addressgroup_block" style="display: none">    
+
+        <div class="row">
+            <div class="col">
+                <p>
+                    <label for="sdaddressgroup_source">select at most one source address-group</label><br>
+                    <select name="sdaddressgroup_source" size="10"  style="width: 200px;">
+                        {% for f in firewall_addressgroup %}
+                        <option>{{ f }}</option>
+                        {% endfor %}      
+                    </select>
+                </p>
+
+            </div>
+
+            <div class="col">
+                <p>
+                    <label for="sdaddressgroup_destination">select at most one destination address-group</label><br>
+                    <select name="sdaddressgroup_destination" size="10" style="width: 200px;">
+                        {% for f in firewall_addressgroup %}
+                        <option>{{ f }}</option>
+                        {% endfor %}        
+                    </select>
+                </p>
+
+
+          </div>
+        </div>
+
+    </div>
+
+    <h3 class="matching_criteria"><input type="checkbox" id="criteria_networkgroup" value="1" name="criteria_networkgroup"> <label for="criteria_networkgroup" class="label_for_h3">Matching criteria - network-group</label></h3>    
+    <div class="container" id="criteria_networkgroup_block" style="display: none">
+        <div class="row">
+            <div class="col">
+                <p>
+                    <label for="sdnetworkgroup_source">select at most one source network-group</label><br>
+                    <select name="sdnetworkgroup_source" size="10" style="width: 200px;">
+                        {% for f in firewall_networkgroup %}
+                        <option>{{ f }}</option>
+                        {% endfor %}
+                    </select>
+                </p>         
+                
+            </div>
+
+            <div class="col">
+                <p>
+                    <label for="sdnetworkgroup_destination">select at most one destination network-group</label><br>
+                    <select name="sdnetworkgroup_destination" size="10" style="width: 200px;">
+                        {% for f in firewall_networkgroup %}
+                        <option>{{ f }}</option>
+                        {% endfor %}
+                    </select>
+                </p>
+
+
+          </div>
+        </div>
+
+    </div>    
+
+    <h3 class="matching_criteria"><input type="checkbox" id="criteria_portgroup" value="1" name="criteria_portgroup"> <label for="criteria_portgroup" class="label_for_h3">Matching criteria - port group</label></h3>    
+    <div class="container" id="criteria_portgroup_block" style="display: none">
+        <div class="row">
+            <div class="col">
+                <p>
+                    <label for="sdportgroup_source">source port group (single choice)</label><br>
+                    <select name="sdportgroup_source" id="sdportgroup_source" size="10" style="width: 200px;">
+                        {% for f in portgroups_groups %}
+                        <option>{{ f }}</option>
+                        {% endfor %}
+                    </select>
+                </p>
+
+            </div>
+
+            <div class="col">
+                <p>
+                    <label for="sdportgroup_destination">destination port group (single choice)</label><br>
+                    <select name="sdportgroup_destination" id="sdportgroup_destination" size="10" style="width: 200px;">
+                        {% for f in portgroups_groups %}
+                        <option>{{ f }}</option>
+                        {% endfor %}
+                    </select>
+                </p>
+
+
+          </div>
+        </div>
+
+    </div>    
+
+    <h3 class="matching_criteria"><input type="checkbox" id="criteria_sourcemac" value="1" name="criteria_sourcemac"> <label for="criteria_sourcemac" class="label_for_h3">Matching criteria - source mac address</label></h3>    
+    <div class="container" id="criteria_sourcemac_block" style="display: none">
+        <div class="row">
+            <div class="col">
+                <p>
+                    <label for="smac_source">mac address</label><br>
+                    <input type="text" name="smac_source" id="smac_source" value="" size="30">
+                </p>
+
+                <p>
+                    <input type="checkbox" name="smac_source_negate" id="smac_source_negate" value="1"> <label for="smac_source_negate">negate source mac address</label>
+                </p>                         
+            </div>
+
+        </div>
+
+    </div>
+
+
+    <h3 class="matching_criteria"><input type="checkbox" id="criteria_packetstate" value="1" name="criteria_packetstate"> <label for="criteria_packetstate" class="label_for_h3">Matching criteria - Packet State</label></h3>    
+    <div class="container" id="criteria_packetstate_block" style="display: none">
+        <div class="row">
+            <div class="col">
+                <p>
+                    <input type="checkbox" name="packetstate_established" id="state_established" value="1"> established
+                    <input type="checkbox" name="packetstate_invalid" id="state_invalid" value="1"> invalid
+                    <input type="checkbox" name="packetstate_new" id="state_new" value="1"> new
+                    <input type="checkbox" name="packetstate_related" id="state_related" value="1"> releated        
+                </p>
+            </div>
+
+        </div>            
+    </div>
     
     
     <input type="submit" value="Add Rule">
     <input type="submit" value="Add Rule">
     </form>
     </form>
 
 
     
     
-    
+<script>
+
+    function isNumeric(n) {
+            return !isNaN(parseFloat(n)) && isFinite(n);
+    }
+
+    $(document).ready(function () {                            
+        $(".protocol_criteria").change(function () {
+            if ($("#protocol_criteria_other").is(":checked")) {
+                $('#protocol_custom_block').show();
+            }
+            else if ($("#addresstype_range").not(":checked")) {
+                $('#protocol_custom_block').hide();
+            }
+
+            protocol_criteria = $('.protocol_criteria:checked').val();
+
+
+            if (['tcp', 'udp', 'tcp_udp'].includes(protocol_criteria) == false) {
+                $("#criteria_port").prop("checked", false);
+                $("#criteria_port_block_header").hide();
+                $("#criteria_port_block").hide();
+            } else {
+                $("#criteria_port_block_header").show("highlight", {color: '#FBE28A'}, 2000);
+            }
+
+            if (['tcp', 'tcp_udp'].includes(protocol_criteria) == false) {
+                $("#criteria_tcpflags_header").hide();
+                $("#criteria_tcpflags_block").hide();
+            } else {
+                $("#criteria_tcpflags_header").show("highlight", {color: '#FBE28A'}, 2000);
+            }
+            
+
+
+        });
+
+        $("#criteria_protocol").change(function () {
+            if ($("#criteria_protocol").is(":checked")) {
+                $('#criteria_protocol_block').show();
+            }
+            else if ($("#criteria_protocol").not(":checked")) {
+                $('#criteria_protocol_block').hide();
+            }
+        });
+
+        $("#criteria_port").change(function () {
+            if ($("#criteria_port").is(":checked")) {
+                $('#criteria_port_block').show();
+            }
+            else if ($("#criteria_port").not(":checked")) {
+                $('#criteria_port_block').hide();
+            }
+        });  
+
+        $("#criteria_address").change(function () {
+            if ($("#criteria_address").is(":checked")) {
+                $('#criteria_address_block').show();
+            }
+            else if ($("#criteria_address").not(":checked")) {
+                $('#criteria_address_block').hide();
+            }
+        });    
+
+        $("#criteria_addressgroup").change(function () {
+            if ($("#criteria_addressgroup").is(":checked")) {
+                $('#criteria_addressgroup_block').show();
+            }
+            else if ($("#criteria_addressgroup").not(":checked")) {
+                $('#criteria_addressgroup_block').hide();
+            }
+        });    
+
+        $("#criteria_networkgroup").change(function () {
+            if ($("#criteria_networkgroup").is(":checked")) {
+                $('#criteria_networkgroup_block').show();
+            }
+            else if ($("#criteria_networkgroup").not(":checked")) {
+                $('#criteria_networkgroup_block').hide();
+            }
+        });   
+
+        $("#criteria_portgroup").change(function () {
+            if ($("#criteria_portgroup").is(":checked")) {
+                $('#criteria_portgroup_block').show();
+            }
+            else if ($("#criteria_portgroup").not(":checked")) {
+                $('#criteria_portgroup_block').hide();
+            }
+        });                                        
+
+        $("#criteria_sourcemac").change(function () {
+            if ($("#criteria_sourcemac").is(":checked")) {
+                $('#criteria_sourcemac_block').show();
+            }
+            else if ($("#criteria_sourcemac").not(":checked")) {
+                $('#criteria_sourcemac_block').hide();
+            }
+        });     
+
+        $("#criteria_tcpflags").change(function () {
+            if ($("#criteria_tcpflags").is(":checked")) {
+                $('#criteria_tcpflags_block').show();
+            }
+            else if ($("#criteria_tcpflags").not(":checked")) {
+                $('#criteria_tcpflags_block').hide();
+            }
+        });
+
+        $("#criteria_packetstate").change(function () {
+            if ($("#criteria_packetstate").is(":checked")) {
+                $('#criteria_packetstate_block').show();
+            }
+            else if ($("#criteria_packetstate").not(":checked")) {
+                $('#criteria_packetstate_block').hide();
+            }
+        });   
+
+        // form basic validations
+        $("#form_addrule").submit(function(e){
+            rulenumber = $('#rulenumber').val();
+            
+
+            if (rulenumber == "" || isNumeric(rulenumber) == false) {
+                alert('Rule number must be definied and be numeric.');
+                e.preventDefault();
+                return false;
+            } else if (rulenumber < 1 && rulenumber > 9999) {
+                alert('Rule number must be between 1 and 9999.');
+                e.preventDefault();
+                return false;
+            }
+            
+            if (!$('.fwaction').is(':checked')){
+                alert('Rule action must be selected.');
+                e.preventDefault();
+                return false;
+            } 
+
+            var destinationport_values = []
+            $("#destinationport option").each(function() {
+                destinationport_values.push($(this).val());
+            });
+            var destinationport_json = JSON.stringify(destinationport_values);
+            $("#destinationport_json").val(destinationport_json);
+
+            var sourceport_values = []
+            $("#sourceport option").each(function() {
+                sourceport_values.push($(this).val());
+            });            
+            var sourceport_json = JSON.stringify(sourceport_values);
+            $("#sourceport_json").val(sourceport_json);
+
+            console.log(sourceport_json)
+
+
+            //e.preventDefault();
+        });
+     
+        $("#sourceport_common_add").click(function () {
+            port = $("#sourceport_common").children("option:selected").val();
+            text = $("#sourceport_common").children("option:selected").text();            
+            if (port == "") {
+                return false;
+            }
+
+            if ($("#sourceport_common_negate").is(":checked")) {
+                negate = "!";
+            } else {
+                negate = "";
+            }
+
+            v = negate + port;
+            t = negate + text;
+
+            if ($("#sourceport option[value='" + v + "']").length == 0) {
+                $('#sourceport').append($('<option>', {
+                    value: v,
+                    text: t
+                }));
+            }
+        });
+
+        $("#sourceport_custom_add").click(function () {
+            port = $("#sourceport_custom").val();
+            if (port == "") {
+                return false;
+            }
+
+            if ($("#sourceport_custom_negate").is(":checked")) {
+                negate = "!";
+            } else {
+                negate = "";
+            }
+
+            port_text = negate + port;
+
+            if ($("#sourceport option[value='" + port_text + "']").length == 0) {
+                $('#sourceport').append($('<option>', {
+                    value: port_text,
+                    text: port_text
+                }));
+            }
+        });
+
+        $("#destinationport_common_add").click(function () {
+            port = $("#destinationport_common").children("option:selected").val();
+            text = $("#destinationport_common").children("option:selected").text();
+            if (port == "") {
+                return false;
+            }
+
+            if ($("#destinationport_common_negate").is(":checked")) {
+                negate = "!";
+            } else {
+                negate = "";
+            }
+
+            v = negate + port;
+            t = negate + text;
+
+            if ($("#destinationport option[value='" + v + "']").length == 0) {
+                $('#destinationport').append($('<option>', {
+                    value: v,
+                    text: t
+                }));
+            }
+        });
+
+        $("#destinationport_custom_add").click(function () {
+            port = $("#destinationport_custom").val();
+            if (port == "") {
+                return false;
+            }
+
+            if ($("#destinationport_custom_negate").is(":checked")) {
+                negate = "!";
+            } else {
+                negate = "";
+            }
+
+            port_text = negate + port;
+
+            if ($("#destinationport option[value='" + port_text + "']").length == 0) {
+                $('#destinationport').append($('<option>', {
+                    value: port_text,
+                    text: port_text
+                }));
+            }
+        });
+
+        $('#sourceport').click(function() {
+            $(this).find('option:selected').remove();
+        });
+
+        $('#destinationport').click(function() {
+            $(this).find('option:selected').remove();
+        });        
+
+ });
+</script>
+          
 
 
 
 
 {% endblock %}
 {% endblock %}

+ 2 - 1
vycontrol/firewall/templates/firewall/create.html

@@ -13,7 +13,8 @@
 <p class="submenu1">
 <p class="submenu1">
     <a href="{% url 'firewall:firewall-list' %}">Firewall List</a> | 
     <a href="{% url 'firewall:firewall-list' %}">Firewall List</a> | 
     <a href="{% url 'firewall:firewall-addressgroup-add' %}">Address Group</a> | 
     <a href="{% url 'firewall:firewall-addressgroup-add' %}">Address Group</a> | 
-    <a href="{% url 'firewall:firewall-networkgroup-list' %}">Network Group</a>
+    <a href="{% url 'firewall:firewall-networkgroup-list' %}">Network Group</a> | 
+    <a href="{% url 'firewall:firewall-portgroup-list' %}">Port Group</a>
 </p>
 </p>
 <p class="submenu2"></p>
 <p class="submenu2"></p>
 
 

+ 8 - 0
vycontrol/firewall/templates/firewall/edit.html

@@ -11,6 +11,14 @@
 
 
 {% block content %}
 {% block content %}
 
 
+<p class="submenu1">
+    <a href="{% url 'firewall:firewall-list' %}">Firewall List</a> | 
+    <a href="{% url 'firewall:firewall-addressgroup-add' %}">Address Group</a> | 
+    <a href="{% url 'firewall:firewall-networkgroup-list' %}">Network Group</a> | 
+    <a href="{% url 'firewall:firewall-portgroup-list' %}">Port Group</a>
+</p>
+<p class="submenu2"></p>
+
 <h2>Firewall {{ firewall_name }}</h2>
 <h2>Firewall {{ firewall_name }}</h2>
 
 
 <form action="{% url 'firewall:firewall-edit' firewall_name %}" method="post">
 <form action="{% url 'firewall:firewall-edit' firewall_name %}" method="post">

+ 945 - 54
vycontrol/firewall/templates/firewall/editrule.html

@@ -1,85 +1,976 @@
 {% extends "base.html" %}
 {% extends "base.html" %}
 
 
-{% block header_title %}Firewall Dashboard{% endblock %}
-{% block section_title %}Firewall Dashboard{% endblock %}
+{% block header_title %}Firewall {{firewall_name}} - rule {{ firewall_rulenumber }}{% endblock %}
+{% block section_title %}<a href="{% url 'firewall:show' firewall_name %}">Firewall {{firewall_name}}</a> - edit rule {{ firewall_rulenumber }}{% endblock %}
 {% block username %}{{ username }}{% endblock %}
 {% block username %}{{ username }}{% endblock %}
 
 
 {% block debug %}
 {% block debug %}
+
 {{ firewall }}
 {{ firewall }}
+
+{{ mode }}
+
+{{ firewall_name }}
+
+{{ services }}
+
+{{ services_common }}
+
+{{ firewall_networkgroup }}
+
+{{ firewall_addressgroup }}
+
+{{ rulenumber }}
+
 {{ firewall_name }}
 {{ firewall_name }}
-{{ firewall_rulenumber }}
-{{ firewall_rule }}
+
+{{ ruledata }}
+
 {% endblock %}
 {% endblock %}
 
 
 {% block content %}
 {% block content %}
 
 
+{% comment %}
+<script type="text/javascript">
+    var firewall_networkgroup_data = '{{firewall_networkgroup_js|safe}}';
+    console.log(firewall_networkgroup_data);
 
 
+    var firewall_addressgroup_data = '{{firewall_addressgroup_js|safe}}';
+    console.log(firewall_addressgroup_data);    
 
 
+    var netservices_js = '{{netservices_js|safe}}';
+    console.log(netservices_js);   
+</script>
+{% endcomment %}
+
+{% if mode == "editrule" %}
+<script type="text/javascript">
+    var ruledata_js = JSON.parse('{{ruledata_json|safe}}');
+</script>
+{% endif %}
 
 
-{% if firewall %}
-    <table border="1" width="100%">
-    <tr><th>rule #</th><th>description</th><th>protocol</th><th>destination port</th><th>source port</th><th>action</th></tr>
 
 
-    {% for key, value in firewall.items %}
-        
-        {% for ifkey, ifvalue in value.items %}
-            <tr>
-            <td><a href="{% url 'firewall:editrule' firewall_name ifkey %}">{{ ifkey }}</a></td>
-            <td>{{ ifvalue.description }}</td>
-            <td>{{ ifvalue.protocol }}</td>
-            <td>{{ ifvalue.destination.port }}</td>
-            <td>{{ ifvalue.source.port }}</td>
-            <td>{{ ifvalue.action }}</td>                        
-            </tr>
-        {% endfor %}
-        
-    {% endfor %}
 
 
-    </table>
-{% else %}
-    <p>No firewalls.</p>
-{% endif %}
 
 
+<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>
+</p>
+<p class="submenu2">
+    <a href="{% url 'firewall:addrule' firewall_name %}">Add new rule</a>
+</p>
 
 
-<h2>Edit rule</h2>
 
 
-<form action="{% url 'firewall:editrule' firewall_name firewall_rulenumber %}" method="post">
+{% if mode == "editrule" %}
+<form action="{% url 'firewall:editrule' firewall_name rulenumber %}" method="post" id="form_change">
+{% elif mode == "addrule" %}
+<form action="{% url 'firewall:addrule' firewall_name  %}" method="post" id="form_change">
+{% endif %}
+
     {% csrf_token %}
     {% csrf_token %}
     
     
-    <p>
-        <label for="alias">rule number</label><br>
-        <input type="text" name="rulenumber" id="rulenumber" value="{{ firewall_rulenumber }}" size="5" disabled>
-    </p>
-    
-    <p>
-        <label for="hostname">action</label><br>
-        <input type="radio" name="action" id="action" value="accept" {% if firewall_rule.action == "accept" %}checked="checked"{% endif %}> accept
-        <input type="radio" name="action" id="action" value="drop" {% if firewall_rule.action == "drop" %}checked="checked"{% endif %}> drop
-        <input type="radio" name="action" id="action" value="reject" {% if firewall_rule.action == "reject" %}checked="checked"{% endif %}> reject        
-    </p>
-
-    <p>
-        <label for="hostname">protocol</label><br>
-        <input type="radio" name="protocol" id="protocol" value="tcp" {% if firewall_rule.protocol == "tcp" %}checked="checked"{% endif %}> tcp
-        <input type="radio" name="protocol" id="protocol" value="udp" {% if firewall_rule.protocol == "udp" %}checked="checked"{% endif %}> udp
-    </p>   
-    
-    <p>
-        <label for="alias">destination port</label><br>
-        <input type="text" name="destinationport" id="destinationport" value="{{ firewall_rule.destination.port }}" size="5">
-    </p>
-    
-    <p>
-        <label for="alias">source port</label><br>
-        <input type="text" name="sourceport" id="sourceport" value="{{ firewall_rule.source.port }}" size="5">
-    </p>    
+
+    <h3>Rule Config</h3>
+    <div class="container">
+        <div class="row">
+
+            {% if mode == "addrule" %}
+            <div class="col">
+                <p>
+                    <label for="alias">rule number</label><br>
+                    <input type="text" name="rulenumber" id="rulenumber" value="{{ rulenumber }}" size="5">
+                </p>
+            </div>
+            {% endif %}
+
+            <div class="col">
+                <p>
+                    <label for="status">status</label><br>
+                    <input type="radio" name="status" id="status_enabled" value="enabled" checked="checked"> enabled
+                    <input type="radio" name="status" id="status_disabled" value="disabled"> disabled
+                </p>
+            </div>         
+
+            <div class="col">
+                <p>
+                    <label for="action">action</label><br>
+                    <input type="radio" class="fwaction" name="ruleaction" id="action" value="accept" {%if ruledata.action == "accept" %}checked{%endif%}> accept
+                    <input type="radio" class="fwaction" name="ruleaction" id="action" value="drop" {%if ruledata.action == "drop" %}checked{%endif%}> drop
+                    <input type="radio" class="fwaction" name="ruleaction" id="action" value="reject" {%if ruledata.action == "reject" %}checked{%endif%}> reject        
+                </p>
+            </div>
+        </div>
+
+        <div class="row">
+            <div class="col">
+                <p>
+                    <label for="alias">description</label><br>
+                    <input type="text" name="description" id="description" value="{{ ruledata.description|default:"" }}" size="60">
+                </p>
+            </div>
+
+
+        </div>       
+    </div>
+
+
+    <h3 class="matching_criteria"><input type="checkbox" name="criteria_protocol" value="1" id="criteria_protocol"> <label for="criteria_protocol" class="label_for_h3">Matching criteria - protocol</label></h3>
+    <div class="container" id="criteria_protocol_block" style="display: none">
+
+        <div class="row">
+
+            <div class="col">
+                <p>
+                    <input type="radio" class="protocol_criteria" name="protocol_criteria" id="protocol_criteria_all" value="all"> all protocols<br>
+                    <input type="radio" class="protocol_criteria" name="protocol_criteria" id="protocol_criteria_tcp" value="tcp"> tcp<br>
+                    <input type="radio" class="protocol_criteria" name="protocol_criteria" id="protocol_criteria_udp" value="udp"> udp<br>
+                    <input type="radio" class="protocol_criteria" name="protocol_criteria" id="protocol_criteria_tcp_udp" value="tcp_udp"> tcp and udp<br>
+                    <input type="radio" class="protocol_criteria" name="protocol_criteria" id="protocol_criteria_icmp" value="icmp"> icmp<br>
+                    <input type="radio" class="protocol_criteria" name="protocol_criteria" id="protocol_criteria_other" value="other"> other  
+                </p>
+
+
+            </div>
+
+            <div class="col">
+                
+
+                <p id="protocol_custom_block" style="display: none">
+                    <label for="protocol_custom">other protocol</label><br>
+                    <input type="text" name="protocol_custom" id="protocol_custom" value="{{ protocol_custom }}" size="5"> 
+                </p>                     
+                    
+                {% comment %}
+                <!-- require https://phabricator.vyos.net/T2451 be fixed -->
+                <p>
+                    <input type="checkbox" name="protocol_negate" id="protocol_negate" value="1">
+                    <label for="protocol_negate">negate </label>
+                </p>
+                {% endcomment %}
+            </div>
+        </div>
+    </div>
+
+    <h3  class="matching_criteria" id="criteria_port_block_header" style="display: none"><input type="checkbox" name="criteria_port" value="1" id="criteria_port"> <label for="criteria_port" class="label_for_h3">Matching criteria - port</label></h3>
+    <div class="container" id="criteria_port_block" style="display: none">
+        <div class="row">  
+            <div class="col">
+
+                
+                <p>
+                    <label for="destinationport_common">common destinations ports to add</label><br>
+                    <select name="destinationport_common" id="destinationport_common" size="1">
+                        <option value="">select one</option>
+                        {% for p in services_common %}
+                        <option value="{{ services|get_item_port:p }}">{{ p }} - {{ services|get_item_port:p }} </option>
+                        {% endfor %}
+                    </select>
+
+                    {% comment %}
+                    <input type="checkbox" name="destinationport_common_negate" id="destinationport_common_negate" value="1">
+                    <label for="destinationport_common_negate">negate </label>
+                    {% endcomment %}
+
+                    <input type="button" name="destinationport_common_add" id="destinationport_common_add" value="add" />
+                </p>
+
+
+                <p>
+                    <label for="destinationport_custom">add custom destination ports (use single 100 or range 100-200)</label><br>
+                    <input type="text" name="destinationport_custom" id="destinationport_custom" value="{{ destinationport_custom }}" size="14"> 
+                    
+                    {% comment %}
+                    <input type="checkbox" name="destinationport_custom_negate" id="destinationport_custom_negate" value="1"> 
+                    <label for="destinationport_custom_negate">negate </label>
+                    {% endcomment %}
+
+                    <input type="button" name="destinationport_custom_add" id="destinationport_custom_add" value="add" />
+                </p>                     
+                
+                <p>
+                    <label for="destinationport">destination ports filtered (click to remove)</label><br>
+                    <select name="destinationport" id="destinationport" size="10" style="width: 200px;">
+                    </select>
+
+
+                    <input type="hidden" name="destinationport_json" id="destinationport_json" value="" >
+                </p>
+                
+
+            </div>
+          
+            <div class="col">
+                <p>
+                    <label for="sourceport_common">common source ports to add</label><br>
+                    <select name="sourceport_common" id="sourceport_common" size="1">
+                        <option value="">select one</option>
+                        {% for p in services_common %}
+                        <option value="{{ services|get_item_port:p }}">{{ p }} - {{ services|get_item_port:p }}</option>
+                        {% endfor %}
+                    </select>
+
+                    <input type="checkbox" name="sourceport_common_negate" id="sourceport_common_negate" value="1">
+                    <label for="sourceport_common_negate">negate </label>
+                    <input type="button" name="sourceport_common_add" id="sourceport_common_add" value="add" />
+                </p>   
+
+                <p>
+                    <label for="sourceport_custom">add custom destination ports (use single 100 or range 100-200)</label><br>
+                    <input type="text" name="sourceport_custom" id="sourceport_custom" value="{{ destinationport_custom }}" size="14"> 
+                    <input type="checkbox" name="sourceport_custom_negate" id="sourceport_custom_negate" value="1"> 
+                    <label for="sourceport_custom_negate">negate </label>
+                    <input type="button" name="sourceport_custom_add" id="sourceport_custom_add" value="add" />
+                </p>       
+               
+                <p>
+                    <label for="sourceport">source ports filtered (click to remove)</label><br>
+                    <select name="sourceport" size="10" style="width: 200px;" id="sourceport">
+                    </select>
+
+                    <input type="hidden" name="sourceport_json" id="sourceport_json" value="" >
+
+
+                </p>
+
+
+            </div>
+        </div>
+
+    </div>
+
+    <h3 class="matching_criteria" id="criteria_tcpflags_header" style="display: none"><input type="checkbox" id="criteria_tcpflags" value="1" name="criteria_tcpflags"> <label for="criteria_tcpflags" class="label_for_h3">Matching criteria - TCP Flags</label></h3>    
+    <div class="container" id="criteria_tcpflags_block" style="display: none">
+        <div class="row">
+            <div class="col">
+                <table width="100%">
+                    <tr>
+                        <th>Allow flag</th>
+                        <th>Negate flag</th>
+                    </tr>
+                    <tr>
+                        <td><input type="checkbox" name="tcpflags_syn" id="tcpflags_syn" value="1"> SYN</td>
+                        <td><input type="checkbox" name="tcpflags_isyn" id="tcpflags_isyn" value="1"> !SYN</td>
+                    </tr>
+                    <tr>
+                        <td><input type="checkbox" name="tcpflags_ack" id="tcpflags_ack" value="1"> ACK</td>
+                        <td><input type="checkbox" name="tcpflags_iack" id="tcpflags_iack" value="1"> !ACK</td>
+                    </tr>
+                    <tr>
+                        <td><input type="checkbox" name="tcpflags_fin" id="tcpflags_fin" value="1"> FIN</td>
+                        <td><input type="checkbox" name="tcpflags_ifin" id="tcpflags_ifin" value="1"> !FIN</td>
+                    </tr>
+                    <tr>
+                        <td><input type="checkbox" name="tcpflags_rst" id="tcpflags_rst" value="1"> RST</td>
+                        <td><input type="checkbox" name="tcpflags_irst" id="tcpflags_irst" value="1"> !RST</td>
+                    </tr>
+                    <tr>
+                        <td><input type="checkbox" name="tcpflags_urg" id="tcpflags_urg" value="1"> URG</td>
+                        <td><input type="checkbox" name="tcpflags_iurg" id="tcpflags_iurg" value="1"> !URG</td>
+                    </tr>
+                    <tr>
+                        <td><input type="checkbox" name="tcpflags_psh" id="tcpflags_psh" value="1"> PSH</td>
+                        <td><input type="checkbox" name="tcpflags_ipsh" id="tcpflags_ipsh" value="1"> !PSH</td>
+                    </tr>
+                    <tr>
+                        <td><input type="checkbox" name="tcpflags_all" id="tcpflags_all" value="1"> ALL</td>
+                        <td><input type="checkbox" name="tcpflags_iall" id="tcpflags_iall" value="1"> !ALL</td>
+                    </tr>                        
+                </table>
+            </div>
+
+        </div>
+    </div>
+
+    <h3 class="matching_criteria"><input type="checkbox" id="criteria_address" value="1" name="criteria_address"> <label for="criteria_address" class="label_for_h3">Matching criteria - address</label></h3>
+    <div class="container" id="criteria_address_block" style="display: none">
+
+        <div class="row">
+            <div class="col">
+                <p>
+                    <label for="sdaddress_source">source address</label><br>
+                    <input type="text" name="sdaddress_source" id="sdaddress_source" value="" size="30">
+                </p>
+
+                <p>
+                    <input type="checkbox" name="sdaddress_source_negate" id="sdaddress_source_negate" value="1"> <label for="sdaddress_source_negate">negate source address</label>
+                </p>         
+            </div>
+
+            <div class="col">
+                <p>
+                    <label for="sdaddress_destination">destination address</label><br>
+                    <input type="text" name="sdaddress_destination" id="sdaddress_destination" value="" size="30">
+                </p>
+
+                <p>
+                    <input type="checkbox" name="sdaddress_destination_negate" id="sdaddress_destination_negate" value="1"> <label for="sdaddress_destination_negate">negate destination address</label>
+                </p>         
+             </div>
+        </div>
+
+
+        <div class="row">
+            <div class="col">    
+                <h4>Valid address examples</h4>
+            </div>
+        </div>
+
+        <div class="row">
+            <div class="col">
+                <dl>
+                    <dt>address</dt>
+                    <dd>192.0.2.1</dd>
+                    <dt>address range</dt>
+                    <dd>192.0.2.0-192.0.2.10</dd>
+                    <dt>CIDR</dt>
+                    <dd>192.0.2.0/24</dd>   
+                </dl>
+            </div>
+        </div>
+    </div>
     
     
+    <h3 class="matching_criteria"><input type="checkbox" id="criteria_addressgroup" value="1" name="criteria_addressgroup"> <label for="criteria_addressgroup" class="label_for_h3">Matching criteria - address-group</label></h3>    
+    <div class="container" id="criteria_addressgroup_block" style="display: none">    
+
+        <div class="row">
+            <div class="col">
+                <p>
+                    <label for="sdaddressgroup_source">single choice - you cannot set a group and an adresss together</label><br>
+                    <select name="sdaddressgroup_source" id="sdaddressgroup_source" size="10"  style="width: 200px;">
+                        {% for f in firewall_addressgroup %}
+                        <option value="{{ f }}">{{ f }}</option>
+                        {% endfor %}      
+                    </select>
+                </p>
+
+            </div>
+
+            <div class="col">
+                <p>
+                    <label for="sdaddressgroup_destination">single choice - you cannot set a group and an adresss together</label><br>
+                    <select name="sdaddressgroup_destination" id="sdaddressgroup_destination" size="10" style="width: 200px;">
+                        {% for f in firewall_addressgroup %}
+                        <option value="{{ f }}">{{ f }}</option>
+                        {% endfor %}        
+                    </select>
+                </p>
+
+
+          </div>
+        </div>
+
+    </div>
+
+    <h3 class="matching_criteria"><input type="checkbox" id="criteria_networkgroup" value="1" name="criteria_networkgroup"> <label for="criteria_networkgroup" class="label_for_h3">Matching criteria - network-group</label></h3>    
+    <div class="container" id="criteria_networkgroup_block" style="display: none">
+        <div class="row">
+            <div class="col">
+                <p>
+                    <label for="sdnetworkgroup_source">select at most one source network-group (can't mix destination address group and address)</label><br>
+                    <select name="sdnetworkgroup_source" id="sdnetworkgroup_source" size="10" style="width: 200px;">
+                        {% for f in firewall_networkgroup %}
+                        <option>{{ f }}</option>
+                        {% endfor %}
+                    </select>
+                </p>         
+                
+            </div>
+
+            <div class="col">
+                <p>
+                    <label for="sdnetworkgroup_destination">select at most one destination network-group (can't mix destination address group and address)</label><br>
+                    <select name="sdnetworkgroup_destination" id="sdnetworkgroup_destination" size="10" style="width: 200px;">
+                        {% for f in firewall_networkgroup %}
+                        <option>{{ f }}</option>
+                        {% endfor %}
+                    </select>
+                </p>
+
+
+          </div>
+        </div>
+
+    </div>    
+
+    <h3 class="matching_criteria"><input type="checkbox" id="criteria_portgroup" value="1" name="criteria_portgroup"> <label for="criteria_portgroup" class="label_for_h3">Matching criteria - port group</label></h3>    
+    <div class="container" id="criteria_portgroup_block" style="display: none">
+        <div class="row">
+            <div class="col">
+                <p>
+                    <label for="sdportgroup_source">source port group (single choice and can't mix source port group and port)</label><br>
+                    <select name="sdportgroup_source" id="sdportgroup_source" size="10" style="width: 200px;">
+                        {% for f in portgroups_groups %}
+                        <option value="{{ f }}">{{ f }}</option>
+                        {% endfor %}
+                    </select>
+                </p>
+
+            </div>
+
+            <div class="col">
+                <p>
+                    <label for="sdportgroup_destination">destination port group (single choice and can't mix destination port group and port)</label><br>
+                    <select name="sdportgroup_destination" id="sdportgroup_destination" size="10" style="width: 200px;">
+                        {% for f in portgroups_groups %}
+                        <option value="{{ f }}">{{ f }}</option>
+                        {% endfor %}
+                    </select>
+                </p>
+
+
+          </div>
+        </div>
+
+    </div>    
+
+    <h3 class="matching_criteria"><input type="checkbox" id="criteria_sourcemac" value="1" name="criteria_sourcemac"> <label for="criteria_sourcemac" class="label_for_h3">Matching criteria - source mac address</label></h3>    
+    <div class="container" id="criteria_sourcemac_block" style="display: none">
+        <div class="row">
+            <div class="col">
+                <p>
+                    <label for="smac_source">mac address</label><br>
+                    <input type="text" name="smac_source" id="smac_source" value="" size="30">
+                </p>
+
+                <p>
+                    <input type="checkbox" name="smac_source_negate" id="smac_source_negate" value="1"> <label for="smac_source_negate">negate source mac address</label>
+                </p>                         
+            </div>
+
+        </div>
+
+    </div>
+
+
+    <h3 class="matching_criteria"><input type="checkbox" id="criteria_packetstate" value="1" name="criteria_packetstate"> <label for="criteria_packetstate" class="label_for_h3">Matching criteria - Packet State</label></h3>    
+    <div class="container" id="criteria_packetstate_block" style="display: none">
+        <div class="row">
+            <div class="col">
+                <p>
+                    <input type="checkbox" name="packetstate_established" id="state_established" value="1"> established
+                    <input type="checkbox" name="packetstate_invalid" id="state_invalid" value="1"> invalid
+                    <input type="checkbox" name="packetstate_new" id="state_new" value="1"> new
+                    <input type="checkbox" name="packetstate_related" id="state_related" value="1"> releated        
+                </p>
+            </div>
+
+        </div>            
+    </div>
     
     
+    {% if mode == "addrule" %}
+    <input type="submit" value="Add Rule">
+    {% else %}
     <input type="submit" value="Edit Rule">
     <input type="submit" value="Edit Rule">
+    {% endif %}
     </form>
     </form>
 
 
     
     
+<script>
+
+    function isNumeric(n) {
+            return !isNaN(parseFloat(n)) && isFinite(n);
+    }
+
+    function protocol_criteria_checktcp(color=true) {
+        protocol_criteria = $('.protocol_criteria:checked').val();
+
+
+        if (['tcp', 'udp', 'tcp_udp'].includes(protocol_criteria) == false) {
+            $("#criteria_port").prop("checked", false);
+            $("#criteria_port_block_header").hide();
+            $("#criteria_port_block").hide();
+        } else {
+            if (color == true) {
+                $("#criteria_port_block_header").show("highlight", {color: '#FBE28A'}, 2000);
+            } else {
+                $("#criteria_port_block_header").show();
+            }
+        }
+
+        if (['tcp', 'tcp_udp'].includes(protocol_criteria) == false) {
+            $("#criteria_tcpflags_header").hide();
+            $("#criteria_tcpflags_block").hide();
+        } else {
+            if (color == true) {
+                $("#criteria_tcpflags_header").show("highlight", {color: '#FBE28A'}, 2000);
+            } else {
+                $("#criteria_tcpflags_header").show();
+            }
+        }
+    }
+
+    $(document).ready(function () {                            
+        $(".protocol_criteria").change(function () {
+            if ($("#protocol_criteria_other").is(":checked")) {
+                $('#protocol_custom_block').show();
+            }
+            else if ($("#addresstype_range").not(":checked")) {
+                $('#protocol_custom_block').hide();
+            }
+
+            protocol_criteria_checktcp();
+        });
+
+        $("#criteria_protocol").change(function () {
+            if ($("#criteria_protocol").is(":checked")) {
+                $('#criteria_protocol_block').show();
+            }
+            else if ($("#criteria_protocol").not(":checked")) {
+                $('#criteria_protocol_block').hide();
+            }
+        });
+
+        $("#criteria_port").change(function () {
+            if ($("#criteria_port").is(":checked")) {
+                $('#criteria_port_block').show();
+            }
+            else if ($("#criteria_port").not(":checked")) {
+                $('#criteria_port_block').hide();
+            }
+        });  
+
+        $("#criteria_address").change(function () {
+            if ($("#criteria_address").is(":checked")) {
+                $('#criteria_address_block').show();
+            }
+            else if ($("#criteria_address").not(":checked")) {
+                $('#criteria_address_block').hide();
+            }
+        });    
+
+        $("#criteria_addressgroup").change(function () {
+            if ($("#criteria_addressgroup").is(":checked")) {
+                $('#criteria_addressgroup_block').show();
+            }
+            else if ($("#criteria_addressgroup").not(":checked")) {
+                $('#criteria_addressgroup_block').hide();
+            }
+        });    
+
+        $("#criteria_networkgroup").change(function () {
+            if ($("#criteria_networkgroup").is(":checked")) {
+                $('#criteria_networkgroup_block').show();
+            }
+            else if ($("#criteria_networkgroup").not(":checked")) {
+                $('#criteria_networkgroup_block').hide();
+            }
+        });   
+
+        $("#criteria_portgroup").change(function () {
+            if ($("#criteria_portgroup").is(":checked")) {
+                $('#criteria_portgroup_block').show();
+            }
+            else if ($("#criteria_portgroup").not(":checked")) {
+                $('#criteria_portgroup_block').hide();
+            }
+        });                                        
+
+        $("#criteria_sourcemac").change(function () {
+            if ($("#criteria_sourcemac").is(":checked")) {
+                $('#criteria_sourcemac_block').show();
+            }
+            else if ($("#criteria_sourcemac").not(":checked")) {
+                $('#criteria_sourcemac_block').hide();
+            }
+        });     
+
+        $("#criteria_tcpflags").change(function () {
+            if ($("#criteria_tcpflags").is(":checked")) {
+                $('#criteria_tcpflags_block').show();
+            }
+            else if ($("#criteria_tcpflags").not(":checked")) {
+                $('#criteria_tcpflags_block').hide();
+            }
+        });
+
+        $("#criteria_packetstate").change(function () {
+            if ($("#criteria_packetstate").is(":checked")) {
+                $('#criteria_packetstate_block').show();
+            }
+            else if ($("#criteria_packetstate").not(":checked")) {
+                $('#criteria_packetstate_block').hide();
+            }
+        });   
+
+        // form basic validations
+        $("#form_change").submit(function(e){
+            rulenumber = $('#rulenumber').val();
+            
+            {% if mode == "addrule" %}
+            if (rulenumber == "" || isNumeric(rulenumber) == false) {
+                alert('Rule number must be definied and be numeric.');
+                e.preventDefault();
+                return false;
+            } else if (rulenumber < 1 && rulenumber > 9999) {
+                alert('Rule number must be between 1 and 9999.');
+                e.preventDefault();
+                return false;
+            }
+            {% endif %}
+            
+            if (!$('.fwaction').is(':checked')){
+                alert('Rule action must be selected.');
+                e.preventDefault();
+                return false;
+            } 
+
+            var destinationport_values = []
+            $("#destinationport option").each(function() {
+                destinationport_values.push($(this).val());
+            });
+            var destinationport_json = JSON.stringify(destinationport_values);
+            $("#destinationport_json").val(destinationport_json);
+
+            var sourceport_values = []
+            $("#sourceport option").each(function() {
+                sourceport_values.push($(this).val());
+            });            
+            var sourceport_json = JSON.stringify(sourceport_values);
+            $("#sourceport_json").val(sourceport_json);
+
+            console.log(sourceport_json)
+
+
+            //e.preventDefault();
+        });
+     
+        $("#sourceport_common_add").click(function () {
+            port = $("#sourceport_common").children("option:selected").val();
+            text = $("#sourceport_common").children("option:selected").text();            
+            if (port == "") {
+                return false;
+            }
+
+            if ($("#sourceport_common_negate").is(":checked")) {
+                negate = "!";
+            } else {
+                negate = "";
+            }
+
+            v = negate + port;
+            t = negate + text;
+
+            if ($('#sourceport').length == 0 || $("#sourceport option[value='" + v + "']").length == 0) {
+                $('#sourceport').append($('<option>', {
+                    value: v,
+                    text: t
+                }));
+            }
+        });
+
+        $("#sourceport_custom_add").click(function () {
+            port = $("#sourceport_custom").val();
+            if (port == "") {
+                return false;
+            }
+
+            if ($("#sourceport_custom_negate").is(":checked")) {
+                negate = "!";
+            } else {
+                negate = "";
+            }
+
+            port_text = negate + port;
+
+            if ($('#sourceport').length == 0 || $("#sourceport option[value='" + port_text + "']").length == 0) {
+                $('#sourceport').append($('<option>', {
+                    value: port_text,
+                    text: port_text
+                }));
+            }
+        });
+
+        $("#destinationport_common_add").click(function () {
+            port = $("#destinationport_common").children("option:selected").val();
+            text = $("#destinationport_common").children("option:selected").text();
+            if (port == "") {
+                return false;
+            }
+
+            if ($("#destinationport_common_negate").is(":checked")) {
+                negate = "!";
+            } else {
+                negate = "";
+            }
+
+            v = negate + port;
+            t = negate + text;
+
+            if ($('#destinationport').length == 0 || $("#destinationport option[value='" + v + "']").length == 0) {
+                $('#destinationport').append($('<option>', {
+                    value: v,
+                    text: t
+                }));
+            }
+        });
+
+        $("#destinationport_custom_add").click(function () {
+            port = $("#destinationport_custom").val();
+            if (port == "") {
+                return false;
+            }
+
+            if ($("#destinationport_custom_negate").is(":checked")) {
+                negate = "!";
+            } else {
+                negate = "";
+            }
+
+            port_text = negate + port;
+
+            if ($('#destinationport').length == 0 || $("#destinationport option[value='" + port_text + "']").length == 0) {
+                $('#destinationport').append($('<option>', {
+                    value: port_text,
+                    text: port_text
+                }));
+            }
+        });
+
+        $('#sourceport').click(function() {
+            $(this).find('option:selected').remove();
+        });
+
+        $('#destinationport').click(function() {
+            $(this).find('option:selected').remove();
+        });             
+
+        // json gives criteria_packetstate
+        criteria_packetstate_lenght = 0
+        for (state in ruledata_js['state']) {
+                if (criteria_packetstate_lenght == 0) {
+                    $('#criteria_packetstate_block').show();
+                    $("#criteria_packetstate").prop("checked", true);
+                }
+                ++criteria_packetstate_lenght;
+
+                if (state == "established") { $("#state_established").prop("checked", true); }
+                if (state == "invalid") { $("#state_invalid").prop("checked", true); }
+                if (state == "new") { $("#state_new").prop("checked", true); }
+                if (state == "related") { $("#state_related").prop("checked", true); }
+        }
+
+        // json gives criteria_protocol
+        protocol = ruledata_js['protocol'];
+
+        if (protocol && protocol.length > 0) {
+                $('#criteria_protocol_block').show();
+                $("#criteria_protocol").prop("checked", true);
+
+                if (protocol == "all") { $("#protocol_criteria_all").prop("checked", true); }
+                if (protocol == "tcp") { 
+                    $("#protocol_criteria_tcp").prop("checked", true); 
+                    criteria_protocol_allowed = 1;
+                    criteria_protocol_tcp_allowed = 1;
+                }
+                if (protocol == "udp") { 
+                    $("#protocol_criteria_udp").prop("checked", true); 
+                    criteria_protocol_allowed = 1;
+                }
+                if (protocol == "tcp_udp") { 
+                    ("#protocol_criteria_tcp_udp").prop("checked", true); 
+                    criteria_protocol_allowed = 1;
+                    criteria_protocol_tcp_allowed = 1;
+                }
+                if (protocol == "icmp") { $("#protocol_criteria_icmp").prop("checked", true); }
+                if (protocol == "other") { $("#protocol_criteria_other").prop("checked", true); }
+
+                protocol_criteria_checktcp(false);
+        }        
+
+        criteria_protocol_count = 0
+        // json gives criteria_protocol destination
+        if (ruledata_js['destination'] && ruledata_js['destination']['port']) {
+            destination_ports = ruledata_js['destination']['port'].split(",");
+            for (p in destination_ports) {
+                port_text = destination_ports[p];
+
+                if ($("#destinationport option[value='" + port_text + "']").length == 0) {
+                    $('#destinationport').append($('<option>', {
+                        value: port_text,
+                        text: port_text
+                    }));
+                    criteria_protocol_count++;
+                }
+            }
+        }
+
+        // json gives criteria_protocol source
+        if (ruledata_js['source'] && ruledata_js['source']['port']) {
+            source_ports = ruledata_js['source']['port'].split(",");
+            for (p in source_ports) {
+                port_text = source_ports[p];
+
+                if ($('#sourceport').length == 0 || $("#sourceport option[value='" + port_text + "']").length == 0) {
+                    $('#sourceport').append($('<option>', {
+                        value: port_text,
+                        text: port_text
+                    }));
+                    criteria_protocol_count++;
+                }
+            }
+        }        
+
+        // enable criteria_procol since source contains tcp
+        if (criteria_protocol_count > 0 && criteria_protocol_allowed == 1) {
+            // $("#criteria_protocol_header").show("highlight", {color: '#FBE28A'}, 2000);
+            $("#criteria_port").prop("checked", true);
+            $("#criteria_port_block").show();
+        }
+
+        // json gives criteria_tcpflags
+        criteria_flags_count = 0
+        if (ruledata_js['tcp'] && ruledata_js['tcp']['flags']) {
+            flags = ruledata_js['tcp']['flags'].split(",");
+            for (p in flags) {
+                flag = flags[p]
+                flag = flag.replace("!", "i").toLowerCase();
+                flag_txt_id = "#tcpflags_" + flag
+                criteria_flags_count++;
+
+                $(flag_txt_id).prop("checked", true);
+            }
+
+        }
+
+        // enable criteria_tcpflags since source contains tcp
+        if (criteria_flags_count > 0 && criteria_protocol_tcp_allowed == 1) {
+            // $("#criteria_protocol_header").show("highlight", {color: '#FBE28A'}, 2000);
+            $("#criteria_tcpflags").prop("checked", true);
+            $("#criteria_tcpflags_block").show();
+        }
+
+        // json gives criteria_address
+        if (
+                (ruledata_js['destination'] && ruledata_js['destination']['address']) || 
+                (ruledata_js['source'] && ruledata_js['source']['address'])
+            ) {
+            $("#criteria_address").prop("checked", true);
+            $("#criteria_address_block").show(); 
+
+
+            var sdaddress_source = ruledata_js['source']['address'];
+            if (sdaddress_source.startsWith("!")) {
+                var sdaddress_source_inverse = 1;
+                sdaddress_source = sdaddress_source.replace("!", "");
+            }
+
+            var sdaddress_destination = ruledata_js['destination']['address'];
+            if (sdaddress_destination.startsWith("!")) {
+                var sdaddress_destination_inverse = 1;
+                sdaddress_destination = sdaddress_destination.replace("!", "");
+            }            
+
+            if (sdaddress_source) {
+                $("#sdaddress_source").val(sdaddress_source)
+            }
+            if (sdaddress_destination) {
+                $("#sdaddress_destination").val(sdaddress_destination)
+            }            
+            if (sdaddress_source_inverse ==1 ) {
+                $("#sdaddress_source_negate").prop("checked", true);
+            }
+            if (sdaddress_destination_inverse ==1 ) {
+                $("#sdaddress_destination_negate").prop("checked", true);
+            }            
+        }
+
+        // json gives criteria_addressgroup or criteria_networkgroup
+        if ($.inArray("destination", ruledata_js) || $.inArray("source", ruledata_js)) { // if was not need only to group block
+            criteria_addressgroup_count = 0;
+            criteria_networkgroup_count = 0;
+            criteria_portgroup_count = 0;
+
+            if ($.inArray("destination", ruledata_js)) {
+    
+                if ($.inArray("group", ruledata_js["destination"])) {
+                    console.log("destination group");
+                    if (ruledata_js["destination"] && ruledata_js["destination"]['group']) {
+                        for (g in ruledata_js["destination"]["group"]) {
+                            group_text = ruledata_js["destination"]["group"][g];
+                            // console.log(g + " = ", group_text)
+
+                            if (g == "address-group") {
+                                criteria_addressgroup_count++;
+                                $("#sdaddressgroup_destination option[value='" + group_text + "']").prop("selected", 'selected');
+                            } else if (g == "network-group") {
+                                criteria_networkgroup_count++;
+                                $("#sdaddressgroup_destination option[value='" + group_text + "']").prop("selected", 'selected');
+                            } else if (g == "port-group") {
+                                criteria_portgroup_count++;
+                                $("#sdportgroup_destination option[value='" + group_text + "']").prop("selected", 'selected');
+                            }                                                
+                        }
+                    }                
+                }
+            }
+            if ($.inArray("source", ruledata_js)) {          
+                if ($.inArray("group", ruledata_js["source"])) {
+                    console.log("source group");
+                    if (ruledata_js["source"] && ruledata_js["source"]['group']) {
+                        for (g in ruledata_js["source"]["group"]) {
+                            group_text = ruledata_js["source"]["group"][g];
+                            console.log(g + " = ", group_text)
+
+                            if (g == "address-group") {
+                                criteria_addressgroup_count++;
+                                $("#sdnetworkgroup_source option[value='" + group_text + "']").prop("selected", 'selected');
+                            } else if (g == "network-group") {
+                                criteria_networkgroup_count++;
+                                $("#sdnetworkgroup_destination option[value='" + group_text + "']").prop("selected", 'selected');
+                            } else if (g == "port-group") {
+                                criteria_networkgroup_count++;
+                                $("#sdportgroup_source option[value='" + group_text + "']").prop("selected", 'selected');
+                            }   
+                        }
+                    }
+                }
+            }        
+            if (criteria_addressgroup_count > 0) {
+                $("#criteria_addressgroup").prop("checked", true);
+                $("#criteria_addressgroup_block").show(); 
+            }
+
+            if (criteria_portgroup_count > 0) {
+                $("#criteria_portgroup").prop("checked", true);
+                $("#criteria_portgroup_block").show(); 
+            }            
+
+            
+        }
+
+        // json gives criteria_sourcemac
+        if ($.inArray("source", ruledata_js)) {
+            var macaddr_inverse = 0;
+            if ($.inArray("mac-address", ruledata_js['source'])) {
+                if (ruledata_js['source'] && ruledata_js['source']['mac-address']) {
+                    macaddr = ruledata_js['source']['mac-address'];
+                    if (macaddr.startsWith("!")) {
+                        var macaddr_inverse = 1;
+                        macaddr = macaddr.replace("!", "");
+                        $('#smac_source_negate').prop("checked", true);
+                    }
+                    $('#smac_source').val(macaddr);
+                    $("#criteria_sourcemac").prop("checked", true);
+                    $("#criteria_sourcemac_block").show(); 
+                    console.log(macaddr);
+                }
+            }
+        }
+
+
+        // check status disable
+        if ($.inArray("disable", ruledata_js)) {
+            $('#status_disabled').prop("checked", true);
+            $('#status_enabled').prop("checked", false);
+        }
+
+ });
+</script>
+          
 
 
 
 
 {% endblock %}
 {% endblock %}

+ 8 - 2
vycontrol/firewall/templates/firewall/list.html

@@ -15,7 +15,8 @@
 <p class="submenu1">
 <p class="submenu1">
     <a href="{% url 'firewall:firewall-create' %}">Create new firewall</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-addressgroup-list' %}">Address Group</a> | 
-    <a href="{% url 'firewall:firewall-networkgroup-list' %}">Network Group</a>
+    <a href="{% url 'firewall:firewall-networkgroup-list' %}">Network Group</a> | 
+    <a href="{% url 'firewall:firewall-portgroup-list' %}">Port Group</a>
 </p>
 </p>
 <p class="submenu2"></p>
 <p class="submenu2"></p>
 
 
@@ -23,7 +24,12 @@
 
 
 {% if firewall_all %}
 {% if firewall_all %}
     <table border="1" width="100%">
     <table border="1" width="100%">
-    <tr><th>name</th><th>description</th><th>default-action</th></th><th>actions</th></tr>
+    <tr>
+        <th>name</th>
+        <th>description</th>
+        <th>default-acton</th>
+        <th>actions</th>
+    </tr>
 
 
     {% for key, value in firewall_all.items %}
     {% for key, value in firewall_all.items %}
         
         

+ 67 - 3
vycontrol/firewall/templates/firewall/networkgroup-add.html

@@ -14,12 +14,13 @@
     <a href="{% url 'firewall:firewall-list' %}">Firewall List</a> | 
     <a href="{% url 'firewall:firewall-list' %}">Firewall List</a> | 
     <a href="{% url 'firewall:firewall-create' %}">Create new firewall</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-addressgroup-list' %}">Address Group</a> |
-    <a href="{% url 'firewall:firewall-networkgroup-list' %}">Network Group</a>
+    <a href="{% url 'firewall:firewall-networkgroup-list' %}">Network Group</a> | 
+    <a href="{% url 'firewall:firewall-portgroup-list' %}">Port Group</a>
 </p>
 </p>
 <p class="submenu2"></p>
 <p class="submenu2"></p>
 
 
 
 
-<form action="{% url 'firewall:firewall-networkgroup-add' %}" method="post">
+<form action="{% url 'firewall:firewall-networkgroup-add' %}" method="post" id="formng">
     {% csrf_token %}
     {% csrf_token %}
 
 
 
 
@@ -35,16 +36,79 @@
     
     
     <p>
     <p>
         <label for="network">network (CIDR notation):</label><br>
         <label for="network">network (CIDR notation):</label><br>
-        <input type="input" name="network" value=""/> (eg 10.10.10.0/24)
+        <input type="input" name="network" id="network" value=""/> (eg 10.10.10.0/24) 
+        <input type="button" value="add" id="networkgroup_add">
     </p>
     </p>
 
 
+    <p>
+        <label for="networkgroup">networks (click to remove)</label><br>
+        <select name="networkgroup" id="networkgroup" size="10" style="width: 200px;">
+        </select>
+
+
+        <input type="hidden" name="networkgroup_json" id="networkgroup_json" value="" >
+    </p>
+
+
     <input type="submit" value="Add Group">
     <input type="submit" value="Add Group">
 </form>
 </form>
 
 
 
 
+<script>
+$(document).ready(function () {
+    $("#networkgroup_add").click(function () {
+        network = $("#network").val();
+
+        if (network !=  "") {
+            if ($("#networkgroup option[value='" + network + "']").length == 0) {
+                $('#networkgroup').append($('<option>', {
+                    value: network,
+                    text: network
+                }));
+            }
+        }
+    });
+
+
+    $('#networkgroup').click(function() {
+            $(this).find('option:selected').remove();
+    });
+
+    // form basic validations
+    $("#formng").submit(function(e){
+        size = $("#networkgroup option").length
+        if (size < 1) {
+            alert('Minimum networks is 1');
+            e.preventDefault();
+            return false;
+        }
+        
+        groupname = $("#name").val()
+        if (groupname.length > 31) {
+            alert('Maximum group name 31 characters or less');
+            e.preventDefault();
+            return false;
+        }
+
+
+
+        var groupa = []
+        $("#networkgroup option").each(function() {
+            groupa.push($(this).val());
+        });
+
+        var groupa_json = JSON.stringify(groupa);
+        $("#networkgroup_json").val(groupa_json);
+
+        console.log(groupa_json)
+    });
+
+})
+
 
 
 
 
 
 
+</script>
 
 
 
 
 {% endblock %}
 {% endblock %}

+ 128 - 0
vycontrol/firewall/templates/firewall/networkgroup-desc.html

@@ -0,0 +1,128 @@
+{% extends "base.html" %}
+
+{% block header_title %}Edit Addressgroup{% endblock %}
+{% block section_title %}Edit Addressgroup{% endblock %}
+{% block username %}{{ username }}{% endblock %}
+
+{% block debug %}
+{{ firewall_all }}
+{{ firewall_networkgroup }}
+{% endblock %}
+
+
+{% block content %}
+
+
+<script type="text/javascript">
+    var networkgroup_data = JSON.parse('{{networks_json|safe}}');
+    console.log(networkgroup_data);
+</script>
+
+<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>
+</p>
+<p class="submenu2">
+    <a href="{% url 'firewall:firewall-networkgroup-add' %}">Add network Group</a>
+</p>
+
+
+
+
+
+<form action="{% url 'firewall:firewall-networkgroup-desc' groupname %}" method="post" id="formng">
+    {% csrf_token %}
+
+    <p>
+        <label for="name">description:</label><br>
+        <input type="input" name="description" id="description" value="{{ groupinfo.description }}" size="100" />
+    </p>
+    
+    <p>
+        <label for="network">network (CIDR notation):</label><br>
+        <input type="input" name="network" id="network" value=""/> (eg 10.10.10.0/24) 
+        <input type="button" value="add" id="networkgroup_add">
+    </p>
+
+    <p>
+        <label for="networkgroup">networks (click to remove)</label><br>
+        <select name="networkgroup" id="networkgroup" size="10" style="width: 200px;">
+        </select>
+
+
+        <input type="hidden" name="networkgroup_json" id="networkgroup_json" value="" >
+    </p>
+
+
+    <input type="submit" value="Edit Group">
+</form>
+
+
+<script>
+$(document).ready(function () {
+
+    for (network in networkgroup_data) {
+        $('#networkgroup').append($('<option>', {
+            value: networkgroup_data[network],
+            text: networkgroup_data[network]
+        }));
+    }
+
+    $("#networkgroup_add").click(function () {
+        network = $("#network").val();
+
+        if (network !=  "") {
+            if ($("#networkgroup option[value='" + network + "']").length == 0) {
+                $('#networkgroup').append($('<option>', {
+                    value: network,
+                    text: network
+                }));
+            }
+        }
+    });
+
+
+    $('#networkgroup').click(function() {
+            $(this).find('option:selected').remove();
+    });
+
+    // form basic validations
+    $("#formng").submit(function(e){
+        size = $("#networkgroup option").length
+        if (size < 1) {
+            alert('Minimum networks is 1');
+            e.preventDefault();
+            return false;
+        }
+        
+        var groupa = []
+        $("#networkgroup option").each(function() {
+            groupa.push($(this).val());
+        });
+
+        var groupa_json = JSON.stringify(groupa);
+        $("#networkgroup_json").val(groupa_json);
+
+        console.log(groupa_json)
+        //e.preventDefault();
+        //return false;
+
+    });
+
+})
+
+
+
+
+</script>
+
+    
+
+
+{% endblock %}
+
+
+

+ 13 - 4
vycontrol/firewall/templates/firewall/networkgroup-list.html

@@ -13,7 +13,8 @@
 <p class="submenu1">
 <p class="submenu1">
     <a href="{% url 'firewall:firewall-list' %}">Firewall List</a> | 
     <a href="{% url 'firewall:firewall-list' %}">Firewall List</a> | 
     <a href="{% url 'firewall:firewall-create' %}">Create new firewall</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-addressgroup-list' %}">Address Group</a> | 
+    <a href="{% url 'firewall:firewall-portgroup-list' %}">Port Group</a>
 </p>
 </p>
 <p class="submenu2">
 <p class="submenu2">
     <a href="{% url 'firewall:firewall-networkgroup-add' %}">Add network Group</a>
     <a href="{% url 'firewall:firewall-networkgroup-add' %}">Add network Group</a>
@@ -22,14 +23,22 @@
 
 
 {% if firewall_networkgroup %}
 {% if firewall_networkgroup %}
     <table border="1" width="100%">
     <table border="1" width="100%">
-        <tr><th width="25%">name</th><th width="25%">network</th><th width="50%">description</th></tr>
+        <tr>
+            <th width="25%">name</th>
+            <th width="30%">description</th>
+            <th width="25%">actions</th>
+        </tr>
 
 
     {% for key, value in firewall_networkgroup.items %}       
     {% for key, value in firewall_networkgroup.items %}       
         {% for ifkey, ifvalue in value.items %}
         {% for ifkey, ifvalue in value.items %}
             <tr>
             <tr>
-                <td>{{ ifkey }}</a></td>
-                <td>{{ ifvalue.network }}</td>
+                <td><a href="{% url 'firewall:firewall-networkgroup-desc' ifkey %}">{{ ifkey }}</a></td>
+                {% comment %}<td>{{ ifvalue.network }}</td>{% endcomment %}
                 <td>{{ ifvalue.description }}</td>
                 <td>{{ ifvalue.description }}</td>
+                <td>
+                    <a href="{% url 'firewall:firewall-networkgroup-desc' ifkey %}">Edit</a> | 
+                    <a href="{% url 'firewall:firewall-networkgroup-del' ifkey %}">Remove</a>
+                </td>                
             </tr>
             </tr>
         {% endfor %}
         {% endfor %}
         
         

+ 190 - 0
vycontrol/firewall/templates/firewall/portgroup-add.html

@@ -0,0 +1,190 @@
+{% extends "base.html" %}
+
+{% block header_title %}Firewall Add New Port Group{% endblock %}
+{% block section_title %}Firewall Add New Port Group{% endblock %}
+{% block username %}{{ username }}{% endblock %}
+
+{% block debug %}
+
+{{ services_common }
+}
+{% 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>
+</p>
+<p class="submenu2"></p>
+
+
+<form action="{% url 'firewall:firewall-portgroup-add' %}" method="post" id="form_addportgroup">
+    <input type="hidden" name="portgroup_ports_hidden" id="portgroup_ports_hidden" value="">
+    {% csrf_token %}
+
+
+    <p>
+    <label for="name">group name:</label><br>
+    <input type="input" name="name" id="name" value="" size="30" />
+    </p>
+
+    <p>
+        <label for="name">description:</label><br>
+        <input type="input" name="description" id="description" value="" size="100" />
+    </p>
+    
+
+    <h3>Ports inside group</h3>
+    <div class="container" id="criteria_port_block">
+        <div class="row">  
+          
+            <div class="col">
+                <p>
+                    <label for="portgroup_common">common source ports to add</label><br>
+                    <select name="portgroup_common" id="portgroup_common" size="1">
+                        <option value="">select one</option>
+                        {% for p in services_common %}
+                        <option value="{{ services|get_item_port:p }}">{{ p }} - {{ services|get_item_port:p }}</option>
+                        {% endfor %}
+                    </select>
+
+                    <input type="checkbox" name="portgroup_common_negate" id="portgroup_common_negate" value="1">
+                    <label for="portgroup_common_negate">negate </label>
+                    <input type="button" name="portgroup_common_add" id="portgroup_common_add" value="add" />
+                </p>   
+
+                <p>
+                    <label for="portgroup_custom">add custom destination ports (use single 100 or range 100-200)</label><br>
+                    <input type="text" name="portgroup_custom" id="portgroup_custom" value="{{ destinationport_custom }}" size="14"> 
+                    <input type="checkbox" name="portgroup_custom_negate" id="portgroup_custom_negate" value="1"> 
+                    <label for="portgroup_custom_negate">negate </label>
+                    <input type="button" name="portgroup_custom_add" id="portgroup_custom_add" value="add" />
+                </p>       
+               
+                <p>
+                    <label for="portgroup">source ports filtered (click to remove)</label><br>
+                    <select name="portgroup" size="10" style="width: 200px;" id="portgroup">
+                    </select>
+                </p>
+
+
+            </div>
+        </div>
+
+    </div>
+
+
+    <input type="submit" value="Add Group">
+</form>
+
+
+
+   
+<script>
+    $(document).ready(function () {            
+        $("#portgroup_common_add").click(function () {
+            port = $("#portgroup_common").children("option:selected").val();
+            if (port == "") {
+                return false;
+            }
+
+            if ($("#portgroup_common_negate").is(":checked")) {
+                negate = "!";
+            } else {
+                negate = "";
+            }
+
+            port_text = negate + port;
+
+            if ($("#portgroup option[value='" + port_text + "']").length == 0) {
+                $('#portgroup').append($('<option>', {
+                    value: port_text,
+                    text: port_text
+                }));
+            }
+        });
+
+        $("#portgroup_custom_add").click(function () {
+            port = $("#portgroup_custom").val();
+            if (port == "") {
+                return false;
+            }
+
+            if ($("#portgroup_custom_negate").is(":checked")) {
+                negate = "!";
+            } else {
+                negate = "";
+            }
+
+            port_text = negate + port;
+
+            if ($("#portgroup option[value='" + port_text + "']").length == 0) {
+                $('#portgroup').append($('<option>', {
+                    value: port_text,
+                    text: port_text
+                }));
+            }
+        });
+
+
+
+        $('#portgroup').click(function() {
+            $(this).find('option:selected').remove();
+        });
+
+
+        $("#portgroup_common, #portgroup_common_negate").keypress(function(event) { 
+            if (event.keyCode === 13) { 
+                $("#portgroup_common_add").click(); 
+                return false;
+            } 
+        }); 
+
+        $("#portgroup_custom, #portgroup_custom_negate").keypress(function(event) { 
+            if (event.keyCode === 13) { 
+                $("#portgroup_custom_add").click(); 
+                return false;
+            } 
+        }); 
+
+        // form basic validations
+        $("#form_addportgroup").submit(function(e){
+            if ($('#name').val().length < 1){
+                alert('Port Group must be definied.');
+                e.preventDefault();
+                return false;
+            }
+
+            var ports = [];
+
+            $("#portgroup option").each(function() {
+                x=$(this).val();
+                ports.push(x);
+            });
+
+            $('#portgroup_ports_hidden').val(JSON.stringify(ports));
+
+            if (ports.length <= 0) {
+                alert('Need at least one port.');
+                e.preventDefault();
+                return false;
+            }
+
+        });
+        
+
+
+
+    });
+</script>
+
+
+{% endblock %}
+
+
+

+ 208 - 0
vycontrol/firewall/templates/firewall/portgroup-edit.html

@@ -0,0 +1,208 @@
+{% extends "base.html" %}
+
+{% block header_title %}Firewall Edit Port Group {{ groupname }}{% endblock %}
+{% block section_title %}Firewall Edit Port Group {{ groupname }}{% endblock %}
+{% block username %}{{ username }}{% endblock %}
+
+{% block debug %}
+
+{{ services_common }}
+
+{{ portgroups_json }}
+
+{{ description }}
+
+
+{% endblock %}
+
+{% block content %}
+
+
+
+<script type="text/javascript">
+    var portgroups_json = JSON.parse('{{portgroups_json|safe}}');
+    console.log(portgroups_json['port']);
+</script>
+
+
+
+<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>
+</p>
+<p class="submenu2"></p>
+
+
+
+
+<form action="{% url 'firewall:firewall-portgroup-edit' groupname %}" method="post" id="form_addportgroup">
+    <input type="hidden" name="portgroup_ports_hidden" id="portgroup_ports_hidden" value="">
+    {% csrf_token %}
+
+
+    <p>
+        <label for="name">description:</label><br>
+        <input type="input" name="description" id="description" value="{{ description }}" size="100" />
+    </p>
+    
+
+
+    <h3>Ports inside group</h3>
+    <div class="container" id="criteria_port_block">
+        <div class="row">  
+          
+            <div class="col">
+                <p>
+                    <label for="portgroup_common">common source ports to add</label><br>
+                    <select name="portgroup_common" id="portgroup_common" size="1">
+                        <option value="">select one</option>
+                        {% for p in services_common %}
+                        <option value="{{ services|get_item_port:p }}">{{ p }} - {{ services|get_item_port:p }}</option>
+                        {% endfor %}
+                    </select>
+
+                    <input type="checkbox" name="portgroup_common_negate" id="portgroup_common_negate" value="1">
+                    <label for="portgroup_common_negate">negate </label>
+                    <input type="button" name="portgroup_common_add" id="portgroup_common_add" value="add" />
+                </p>   
+
+                <p>
+                    <label for="portgroup_custom">add custom destination ports (use single 100 or range 100-200)</label><br>
+                    <input type="text" name="portgroup_custom" id="portgroup_custom" value="{{ destinationport_custom }}" size="14"> 
+                    <input type="checkbox" name="portgroup_custom_negate" id="portgroup_custom_negate" value="1"> 
+                    <label for="portgroup_custom_negate">negate </label>
+                    <input type="button" name="portgroup_custom_add" id="portgroup_custom_add" value="add" />
+                </p>       
+               
+                <p>
+                    <label for="portgroup">source ports filtered (click to remove)</label><br>
+                    <select name="portgroup" size="10" style="width: 200px;" id="portgroup">
+                    </select>
+                </p>
+
+
+            </div>
+        </div>
+
+    </div>
+
+
+    <input type="submit" value="Edit Group">
+</form>
+
+
+
+   
+<script>
+    $(document).ready(function () {  
+        
+        for (var port in portgroups_json["port"]) {
+            port_text = portgroups_json["port"][port];
+
+            if ($("#portgroup option[value='" + port_text + "']").length == 0) {
+                $('#portgroup').append($('<option>', {
+                    value: port_text,
+                    text: port_text
+                }));
+            }
+        }
+
+
+        $("#portgroup_common_add").click(function () {
+            port = $("#portgroup_common").children("option:selected").val();
+            if (port == "") {
+                return false;
+            }
+
+            if ($("#portgroup_common_negate").is(":checked")) {
+                negate = "!";
+            } else {
+                negate = "";
+            }
+
+            port_text = negate + port;
+
+            if ($("#portgroup option[value='" + port_text + "']").length == 0) {
+                $('#portgroup').append($('<option>', {
+                    value: port_text,
+                    text: port_text
+                }));
+            }
+        });
+
+        $("#portgroup_custom_add").click(function () {
+            port = $("#portgroup_custom").val();
+            if (port == "") {
+                return false;
+            }
+
+            if ($("#portgroup_custom_negate").is(":checked")) {
+                negate = "!";
+            } else {
+                negate = "";
+            }
+
+            port_text = negate + port;
+
+            if ($("#portgroup option[value='" + port_text + "']").length == 0) {
+                $('#portgroup').append($('<option>', {
+                    value: port_text,
+                    text: port_text
+                }));
+            }
+        });
+
+
+
+        $('#portgroup').click(function() {
+            $(this).find('option:selected').remove();
+        });
+
+
+        $("#portgroup_common, #portgroup_common_negate").keypress(function(event) { 
+            if (event.keyCode === 13) { 
+                $("#portgroup_common_add").click(); 
+                return false;
+            } 
+        }); 
+
+        $("#portgroup_custom, #portgroup_custom_negate").keypress(function(event) { 
+            if (event.keyCode === 13) { 
+                $("#portgroup_custom_add").click(); 
+                return false;
+            } 
+        }); 
+
+        // form basic validations
+        $("#form_addportgroup").submit(function(e){
+            var ports = [];
+
+            $("#portgroup option").each(function() {
+                x=$(this).val();
+                ports.push(x);
+            });
+
+            $('#portgroup_ports_hidden').val(JSON.stringify(ports));
+
+            if (ports.length <= 0) {
+                alert('Need at least one port.');
+                e.preventDefault();
+                return false;
+            }
+
+        });
+        
+
+
+
+    });
+</script>
+
+
+{% endblock %}
+
+
+

+ 56 - 0
vycontrol/firewall/templates/firewall/portgroup-list.html

@@ -0,0 +1,56 @@
+{% extends "base.html" %}
+
+{% block header_title %}Firewall Group List{% endblock %}
+{% block section_title %}Firewall Group List{% endblock %}
+{% block username %}{{ username }}{% endblock %}
+
+{% block debug %}
+{{ firewall_portgroup }}
+{% 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> 
+</p>
+<p class="submenu2">
+    <a href="{% url 'firewall:firewall-portgroup-add' %}">Add port group</a>
+</p>
+
+
+{% if firewall_portgroup %}
+    <table border="1" width="100%">
+        <tr>
+            <th width="25%">name</th>
+            <th width="30%">description</th>
+            <th width="25%">actions</th>
+        </tr>
+
+    {% for key, value in firewall_portgroup.items %}       
+        {% for ifkey, ifvalue in value.items %}
+            <tr>
+                <td><a href="{% url 'firewall:firewall-portgroup-edit' ifkey %}">{{ ifkey }}</a></td>
+                <td>{{ ifvalue.description }}</td>
+                <td>
+                    <a href="{% url 'firewall:firewall-portgroup-edit' ifkey %}">Edit</a> | 
+                    <a href="{% url 'firewall:firewall-portgroup-del' ifkey %}">Remove</a>
+                </td>                
+            </tr>
+        {% endfor %}
+        
+    {% endfor %}
+
+    </table>
+{% else %}
+    <p>No port groups.</p>
+{% endif %}
+
+
+
+{% endblock %}
+
+
+

+ 17 - 4
vycontrol/firewall/templates/firewall/show.html

@@ -12,9 +12,11 @@
 {% block content %}
 {% block content %}
 
 
 <p class="submenu1">
 <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-create' %}">Create new firewall</a> | 
     <a href="{% url 'firewall:firewall-addressgroup-list' %}">Address Group</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-networkgroup-list' %}">Network Group</a> | 
+    <a href="{% url 'firewall:firewall-portgroup-list' %}">Port Group</a>
 </p>
 </p>
 <p class="submenu2">
 <p class="submenu2">
     <a href="{% url 'firewall:addrule' firewall_name %}">Add new rule</a>
     <a href="{% url 'firewall:addrule' firewall_name %}">Add new rule</a>
@@ -42,18 +44,29 @@
 
 
 {% if firewall.rule %}
 {% if firewall.rule %}
     <table border="1" width="100%">
     <table border="1" width="100%">
-    <tr><th>rule #</th><th>description</th><th>protocol</th><th>destination port</th><th>source port</th><th>firewall action</th></tr>
+    <tr>
+        <th>rule #</th>
+        <th>description</th>
+        <th>default action</th>
+        <th>admin action</th>
+    </tr>
 
 
     {% for key, value in firewall.items %}
     {% for key, value in firewall.items %}
         
         
         {% for ifkey, ifvalue in value.items %}
         {% for ifkey, ifvalue in value.items %}
             <tr>
             <tr>
-            <td><a href="{% url 'firewall:editrule' firewall_name ifkey %}">{{ ifkey }}</a> <a href="{% url 'firewall:firewall-removerule' firewall_name ifkey %}">remove rule</a></td>
+            <td><a href="{% url 'firewall:editrule' firewall_name ifkey %}">{{ ifkey }}</a></td>
             <td>{{ ifvalue.description }}</td>
             <td>{{ ifvalue.description }}</td>
+            {% comment %}
             <td>{{ ifvalue.protocol }}</td>
             <td>{{ ifvalue.protocol }}</td>
             <td>{{ ifvalue.destination.port }}</td>
             <td>{{ ifvalue.destination.port }}</td>
             <td>{{ ifvalue.source.port }}</td>
             <td>{{ ifvalue.source.port }}</td>
-            <td>{{ ifvalue.action }}</td>                        
+            {% endcomment %}
+            <td>{{ ifvalue.action }}</td>       
+            <td>
+                <a href="{% url 'firewall:editrule' firewall_name ifkey %}">edit</a> | 
+                <a href="{% url 'firewall:firewall-removerule' firewall_name ifkey %}">remove</a>
+            </td>
             </tr>
             </tr>
         {% endfor %}
         {% endfor %}
         
         

+ 10 - 1
vycontrol/firewall/urls.py

@@ -14,17 +14,26 @@ urlpatterns = [
     path('firewall-edit/<str:firewall_name>', views.firewall_edit, name='firewall-edit'),
     path('firewall-edit/<str:firewall_name>', views.firewall_edit, name='firewall-edit'),
     path('firewall-config/<str:firewall_name>', views.firewall_config, name='firewall-config'),
     path('firewall-config/<str:firewall_name>', views.firewall_config, name='firewall-config'),
     path('firewall-global', views.firewall_global, name='firewall-global'),
     path('firewall-global', views.firewall_global, name='firewall-global'),
+
     path('firewall-addressgroup-list', views.firewall_addressgroup_list, name='firewall-addressgroup-list'),
     path('firewall-addressgroup-list', views.firewall_addressgroup_list, name='firewall-addressgroup-list'),
     path('firewall-addressgroup-add', views.firewall_addressgroup_add, name='firewall-addressgroup-add'),
     path('firewall-addressgroup-add', views.firewall_addressgroup_add, name='firewall-addressgroup-add'),
+    path('firewall-addressgroup-del/<str:groupname>', views.firewall_addressgroup_del, name='firewall-addressgroup-del'),
+    path('firewall-addressgroup-desc/<str:groupname>', views.firewall_addressgroup_desc, name='firewall-addressgroup-desc'),
 
 
     path('firewall-networkgroup-list', views.firewall_networkgroup_list, name='firewall-networkgroup-list'),
     path('firewall-networkgroup-list', views.firewall_networkgroup_list, name='firewall-networkgroup-list'),
     path('firewall-networkgroup-add', views.firewall_networkgroup_add, name='firewall-networkgroup-add'),
     path('firewall-networkgroup-add', views.firewall_networkgroup_add, name='firewall-networkgroup-add'),
+    path('firewall-networkgroup-del/<str:groupname>', views.firewall_networkgroup_del, name='firewall-networkgroup-del'),
+    path('firewall-networkgroup-desc/<str:groupname>', views.firewall_networkgroup_desc, name='firewall-networkgroup-desc'),    
 
 
+    path('firewall-portgroup-list', views.firewall_portgroup_list, name='firewall-portgroup-list'),
+    path('firewall-portgroup-add', views.firewall_portgroup_add, name='firewall-portgroup-add'),
+    path('firewall-portgroup-del/<str:groupname>', views.firewall_portgroup_del, name='firewall-portgroup-del'),
+    path('firewall-portgroup-edit/<str:groupname>', views.firewall_portgroup_edit, name='firewall-portgroup-edit'),
 
 
 
 
 
 
     path('addrule/<str:firewall_name>', views.addrule, name='addrule'),
     path('addrule/<str:firewall_name>', views.addrule, name='addrule'),
-    path('editrule/<str:firewall_name>/<str:firewall_rulenumber>', views.editrule, name='editrule'),
+    path('editrule/<str:firewall_name>/<str:rulenumber>', views.editrule, name='editrule'),
     path('firewall-removerule/<str:firewall_name>/<str:firewall_rulenumber>', views.firewall_removerule, name='firewall-removerule'),    
     path('firewall-removerule/<str:firewall_name>/<str:firewall_rulenumber>', views.firewall_removerule, name='firewall-removerule'),    
 
 
 ]
 ]

文件差异内容过多而无法显示
+ 924 - 117
vycontrol/firewall/views.py


+ 11 - 4
vycontrol/interface/views.py

@@ -9,6 +9,7 @@ from django.template.defaultfilters import register
 
 
 import vyos
 import vyos
 from perms import is_authenticated
 from perms import is_authenticated
+import perms
 
 
 
 
 from config.models import Instance
 from config.models import Instance
@@ -27,6 +28,7 @@ def index(request):
     all_instances = vyos.instance_getall()
     all_instances = vyos.instance_getall()
     firewall_all = vyos.get_firewall_all(hostname_default)
     firewall_all = vyos.get_firewall_all(hostname_default)
     interfaces = vyos.get_interfaces(hostname_default)
     interfaces = vyos.get_interfaces(hostname_default)
+    is_superuser = perms.get_is_superuser(request.user)
 
 
     interface_firewall_in = {}
     interface_firewall_in = {}
     interface_firewall_out = {}
     interface_firewall_out = {}
@@ -104,7 +106,8 @@ def index(request):
         'firewall_all' : firewall_all,
         'firewall_all' : firewall_all,
         'interface_firewall_in' : interface_firewall_in,
         'interface_firewall_in' : interface_firewall_in,
         'interface_firewall_out' : interface_firewall_out,
         'interface_firewall_out' : interface_firewall_out,
-        'username': request.user,        
+        'username': request.user,   
+        'is_superuser' : is_superuser,     
     }
     }
     return HttpResponse(template.render(context, request))
     return HttpResponse(template.render(context, request))
 
 
@@ -115,7 +118,8 @@ def interfaceshow(request, interface_type, interface_name):
     hostname_default = vyos.get_hostname_prefered(request)
     hostname_default = vyos.get_hostname_prefered(request)
     firewall_all = vyos.get_firewall_all(hostname_default)   
     firewall_all = vyos.get_firewall_all(hostname_default)   
     interface = vyos.get_interface(interface_type, interface_name, hostname=hostname_default)
     interface = vyos.get_interface(interface_type, interface_name, hostname=hostname_default)
-    
+    is_superuser = perms.get_is_superuser(request.user)
+  
     template = loader.get_template('interface/show.html')
     template = loader.get_template('interface/show.html')
     context = { 
     context = { 
         'interface': interface,
         'interface': interface,
@@ -124,7 +128,8 @@ def interfaceshow(request, interface_type, interface_name):
         'interface_name' : interface_name,
         'interface_name' : interface_name,
         'hostname_default': hostname_default,
         'hostname_default': hostname_default,
         'firewall_all' : firewall_all,
         'firewall_all' : firewall_all,
-        'username': request.user,                       
+        'username': request.user,        
+        'is_superuser' : is_superuser,               
     }   
     }   
     return HttpResponse(template.render(context, request))
     return HttpResponse(template.render(context, request))
 
 
@@ -133,6 +138,7 @@ def interfaceshow(request, interface_type, interface_name):
 def interfacefirewall(request, interface_type, interface_name):
 def interfacefirewall(request, interface_type, interface_name):
         
         
     all_instances = vyos.instance_getall()
     all_instances = vyos.instance_getall()
+    is_superuser = perms.get_is_superuser(request.user)
 
 
     hostname_default = vyos.get_hostname_prefered(request)
     hostname_default = vyos.get_hostname_prefered(request)
     
     
@@ -145,7 +151,8 @@ def interfacefirewall(request, interface_type, interface_name):
         'hostname_default': hostname_default,
         'hostname_default': hostname_default,
         'interface_type' : interface_type,
         'interface_type' : interface_type,
         'interface_name' : interface_name,        
         'interface_name' : interface_name,        
-        'username': request.user,        
+        'username': request.user,      
+        'is_superuser' : is_superuser,  
     }   
     }   
     return HttpResponse(template.render(context, request))
     return HttpResponse(template.render(context, request))
 
 

+ 127 - 0
vycontrol/network.py

@@ -0,0 +1,127 @@
+import sys
+import socket
+import pprint
+import re
+
+def get_protocols():
+    file = '/etc/protocols'
+    
+    protocols = {}
+    # Iterate through the file, one line at a time
+    for line in open(file):
+        line = line.replace("'","")
+        line = line.replace('"',"")
+        if line[0:1] != '#' and not line.isspace():
+            linesplited = re.split(r'([\t\s]+)', line, maxsplit=2)
+            #pprint.pprint(linesplited)
+            protocol_name = linesplited[0].strip()
+            protocol_id = linesplited[2].strip()
+            protocols[protocol_id] = protocol_name
+            #print(linesplited[0], linesplited[2])
+
+    #pprint.pprint(protocols)
+
+    inv_map = {v: k for k, v in protocols.items()}
+
+    common = ['tcp', 'udp', 'icmp', 'gre', 'ospf', 'igmp', 'egp', 'igp', 'ipv6', 'ip', 'isis']
+
+    return {'all_by_id': protocols, 'all_by_name': inv_map, 'common': common}
+
+def get_services():
+    # set the file name depending on the operating system
+    if sys.platform == 'win32':
+        file = r'C:\WINDOWS\system32\drivers\etc\services'
+    else:
+        file = '/etc/services'
+
+    def is_number(s):
+        try:
+            complex(s) # for int, long, float and complex
+        except ValueError:
+            return False
+
+        return True
+
+
+    protocols = []
+    service_name = {}
+    portprotocol = {}
+
+    # Iterate through the file, one line at a time
+    for line in open(file):
+        line = line.replace("'","")
+        line = line.replace('"',"")
+
+
+
+        if line[0:1] != '#' and not line.isspace():
+            #pprint.pprint(line.strip())
+
+
+            linesplited = re.split(r'([\t\s]+)', line, maxsplit=2)
+            linesplited_clean = {}
+            #pprint.pprint(linesplited)
+            x = 0
+            service_name_actual = None
+            for line_clean in linesplited:
+                line_clean = re.sub('#', '', line_clean.strip())
+                line_clean_strip = re.sub(r'\s+', '', line_clean)
+
+                if x == 0 and line_clean_strip == "":
+                    linesplited_clean['service_name'] = None
+                elif x == 0 and is_number(line_clean_strip) == False: 
+                    linesplited_clean['service_name'] = line_clean_strip
+                    service_name_actual = line_clean_strip
+                    service_name[line_clean_strip] = {}
+
+                    #print('isnumberfalse', is_number(line_clean_strip), line_clean_strip)
+                elif x == 2 and len(line_clean_strip) > 0:
+                    linesplited_clean['port_protocol'] = line_clean_strip
+                    
+                    portprotocol = line_clean_strip.split('/')
+                    linesplited_clean['port'] = portprotocol[0]
+                    linesplited_clean['protocol'] = portprotocol[1]
+
+                    if str(portprotocol[1]) not in protocols:
+                        protocols.append(str(portprotocol[1]))
+
+                    if service_name_actual != None:
+                        service_name[service_name_actual]['p'] = str(portprotocol[1])
+                        service_name[service_name_actual]['n'] = str(portprotocol[0])
+
+                elif x == 4 and len(line_clean_strip) > 0:
+                    linesplited_clean['description'] = line_clean_strip
+                    if service_name_actual != None:
+                        service_name[service_name_actual]['d'] = line_clean_strip
+
+                #re.sub('#', '', line_clean_strip)
+
+                x = x + 1
+            #pprint.pprint(linesplited_clean)
+            #print("#####################")
+
+    common = {
+        'http' : 'http',
+        'https' : 'https',
+        'ftp' : 'ftp',
+        'ftp-data' : 'ftp-data',
+        'ssh' : 'ssh',
+        'telnet' : 'telnet',
+        'smtp' : 'smtp', 
+        'nicname' : 'whois',
+        'domain' : 'dns',
+        'pop3' : 'pop3',
+        'sftp' : 'sftp',
+        'ntp' : 'ntp',
+        'snmp' : 'snmp',
+        'snmptrap' : 'snmptrap',
+        'bgp' : 'bgp',
+        'imaps' : 'imaps',
+        'pop3s' : 'pop3s',
+        'ftps-data' : 'ftps-data',
+        'ftps' : 'ftps',
+        'pop3s' : 'pop3s',
+    }
+
+    return {'protocols': protocols, 'services': service_name, 'common': common}
+

+ 17 - 0
vycontrol/s/main.css

@@ -89,6 +89,13 @@ form.instancedefault {
   font-size: 14px;
   font-size: 14px;
 }
 }
 
 
+#central h4 {
+  margin-top: 10px;
+  font-size: 13px;
+  font-weight: bold;
+}
+
+
 #central {
 #central {
   font-size: 12px;
   font-size: 12px;
 }
 }
@@ -104,6 +111,8 @@ form.instancedefault {
 input[type=submit] {
 input[type=submit] {
   background-color: #EACD65;
   background-color: #EACD65;
   border: 0;
   border: 0;
+  margin-bottom: 20px;
+  margin-top: 20px;
 }
 }
 
 
 .separe-form {
 .separe-form {
@@ -145,3 +154,11 @@ input[type=submit] {
   margin-right: 10px;
   margin-right: 10px;
   color:#af1d1d ;
   color:#af1d1d ;
 }
 }
+
+.label_for_h3 {
+  margin-bottom: 0;
+}
+
+.matching_criteria { 
+  padding: 3px;
+}

+ 6 - 1
vycontrol/static/views.py

@@ -8,6 +8,7 @@ from django.urls import reverse
 import vyos
 import vyos
 from perms import is_authenticated
 from perms import is_authenticated
 from filters.vycontrol_filters import routeunpack
 from filters.vycontrol_filters import routeunpack
+import perms
 
 
 
 
 @is_authenticated    
 @is_authenticated    
@@ -15,6 +16,8 @@ def static_list(request):
     all_instances = vyos.instance_getall()
     all_instances = vyos.instance_getall()
     hostname_default = vyos.get_hostname_prefered(request)
     hostname_default = vyos.get_hostname_prefered(request)
     static_dict = vyos.get_route_static(hostname_default)
     static_dict = vyos.get_route_static(hostname_default)
+    is_superuser = perms.get_is_superuser(request.user)
+
     static_list = []
     static_list = []
     for s in static_dict['route']:
     for s in static_dict['route']:
         static_list.append({
         static_list.append({
@@ -28,6 +31,7 @@ def static_list(request):
         'hostname_default': hostname_default,
         'hostname_default': hostname_default,
         'static_list' : static_list,
         'static_list' : static_list,
         'username': request.user,
         'username': request.user,
+        'is_superuser' : is_superuser,     
     }   
     }   
     return HttpResponse(template.render(context, request))
     return HttpResponse(template.render(context, request))
 
 
@@ -38,7 +42,7 @@ def static_add(request):
     all_instances = vyos.instance_getall()
     all_instances = vyos.instance_getall()
     hostname_default = vyos.get_hostname_prefered(request)
     hostname_default = vyos.get_hostname_prefered(request)
     static_list = vyos.get_route_static(hostname_default)
     static_list = vyos.get_route_static(hostname_default)
-
+    is_superuser = perms.get_is_superuser(request.user)
 
 
 
 
     error_message = None
     error_message = None
@@ -59,6 +63,7 @@ def static_add(request):
         'static_list' : static_list,
         'static_list' : static_list,
         'error_message' : error_message,
         'error_message' : error_message,
         'username': request.user,
         'username': request.user,
+        'is_superuser' : is_superuser,     
     }   
     }   
     return HttpResponse(template.render(context, request))
     return HttpResponse(template.render(context, request))
 
 

+ 6 - 1
vycontrol/vycenter/templates/base.html

@@ -5,12 +5,17 @@
     <!-- Required meta tags -->
     <!-- Required meta tags -->
     <meta charset="utf-8">
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon"> 
 
 
     <!-- Bootstrap CSS -->
     <!-- Bootstrap CSS -->
     <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
     <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
-    <link rel="stylesheet" href="{% static "main.css" %}?17">
+    <link rel="stylesheet" href="{% static "main.css" %}?20">
     <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
     <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
 
 
+    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
+    <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css">
+
+
     <title>{% block header_title %}{% endblock %} - VyControl</title>
     <title>{% block header_title %}{% endblock %} - VyControl</title>
   </head>
   </head>
   <body >
   <body >

+ 63 - 9
vycontrol/vyos.py

@@ -19,8 +19,6 @@ def get_hostname_prefered(*args, **kwargs):
 def instance_getall_by_group(*args, **kwargs):
 def instance_getall_by_group(*args, **kwargs):
     return perms.instance_getall_by_group(*args, **kwargs)
     return perms.instance_getall_by_group(*args, **kwargs)
 
 
-
-
 def repvar(s):
 def repvar(s):
     return s.replace("-", "_")
     return s.replace("-", "_")
 
 
@@ -78,7 +76,7 @@ def api(type, hostname, cmd):
     print(post)   
     print(post)   
 
 
     try:
     try:
-        resp = requests.post(url, verify=False, data=post, timeout=5)
+        resp = requests.post(url, verify=False, data=post, timeout=10)
     except requests.exceptions.ConnectionError:
     except requests.exceptions.ConnectionError:
         return False
         return False
 
 
@@ -136,10 +134,6 @@ def conntry(hostname):
     return False
     return False
 
 
 
 
-
-
-
-
 def get_firewall_all(hostname):
 def get_firewall_all(hostname):
     cmd = {"op": "showConfig", "path": ["firewall"]}
     cmd = {"op": "showConfig", "path": ["firewall"]}
     firewall_list = api_get(hostname, cmd)
     firewall_list = api_get(hostname, cmd)
@@ -239,18 +233,65 @@ def set_firewall_allping_disable(hostname):
     result1 = api_set(hostname, cmd)
     result1 = api_set(hostname, cmd)
     return result1  
     return result1  
 
 
+def get_firewall_portgroup(hostname):
+    cmd = {"op": "showConfig", "path": ["firewall","group","port-group"]}
+    result1 = api_get(hostname, cmd)
+    return result1
+
+def set_firewall_portgroup_del(hostname, group_name):
+    cmd = {"op": "delete", "path": ["firewall","group",'port-group', group_name]}
+    result1 = api_set(hostname, cmd)
+    return result1 
+
+def set_firewall_portgroup_description(hostname, group_name, description):
+    cmd = {"op": "set", "path": ["firewall","group",'port-group', group_name, "description", description]}
+    result1 = api_set(hostname, cmd)
+    return result1 
+
+def set_firewall_portgroup_add(hostname, group_name, port):
+    cmd = {"op": "set", "path": ["firewall","group",'port-group', group_name, "port", port]}
+
+    result1 = api_set(hostname, cmd)
+    return result1    
+
+def set_firewall_portgroup_delete_port(hostname, group_name, port):
+    cmd = {"op": "delete", "path": ["firewall","group",'port-group', group_name, "port", port]}
+
+    result1 = api_set(hostname, cmd)
+    return result1         
+
 def get_firewall_addressgroup(hostname):
 def get_firewall_addressgroup(hostname):
     cmd = {"op": "showConfig", "path": ["firewall","group","address-group"]}
     cmd = {"op": "showConfig", "path": ["firewall","group","address-group"]}
-
     result1 = api_get(hostname, cmd)
     result1 = api_get(hostname, cmd)
-    return result1
+    return result1    
 
 
 def get_firewall_networkgroup(hostname):
 def get_firewall_networkgroup(hostname):
     cmd = {"op": "showConfig", "path": ["firewall","group","network-group"]}
     cmd = {"op": "showConfig", "path": ["firewall","group","network-group"]}
+    result1 = api_get(hostname, cmd)
+    return result1
 
 
+def get_firewall_addressgroup_one(hostname, group_name):
+    cmd = {"op": "showConfig", "path": ["firewall","group","address-group", group_name]}
     result1 = api_get(hostname, cmd)
     result1 = api_get(hostname, cmd)
     return result1
     return result1
 
 
+def get_firewall_networkgroup_one(hostname, group_name):
+    cmd = {"op": "showConfig", "path": ["firewall","group","network-group", group_name]}
+    result1 = api_get(hostname, cmd)
+    return result1
+
+
+def set_firewall_networkgroup_description(hostname, group_name, description):
+    cmd = {"op": "set", "path": ["firewall","group",'network-group', group_name, "description", description]}
+    result1 = api_set(hostname, cmd)
+    return result1 
+
+def set_firewall_addressgroup_description(hostname, group_name, description):
+    cmd = {"op": "set", "path": ["firewall","group",'address-group', group_name, "description", description]}
+    result1 = api_set(hostname, cmd)
+    return result1     
+
+
 
 
 def set_firewall_addressgroup_add(hostname, group_name, address):
 def set_firewall_addressgroup_add(hostname, group_name, address):
     cmd = {"op": "set", "path": ["firewall","group",'address-group', group_name, "address", address]}
     cmd = {"op": "set", "path": ["firewall","group",'address-group', group_name, "address", address]}
@@ -258,6 +299,19 @@ def set_firewall_addressgroup_add(hostname, group_name, address):
     result1 = api_set(hostname, cmd)
     result1 = api_set(hostname, cmd)
     return result1 
     return result1 
 
 
+def set_firewall_addressgroup_del(hostname, group_name):
+    cmd = {"op": "delete", "path": ["firewall","group",'address-group', group_name]}
+    result1 = api_set(hostname, cmd)
+    return result1 
+
+def set_firewall_networkgroup_del(hostname, group_name):
+    cmd = {"op": "delete", "path": ["firewall","group",'network-group', group_name]}
+    result1 = api_set(hostname, cmd)
+    return result1 
+
+
+
+
 def set_firewall_addressgroup_rangeadd(hostname, group_name, address_start, address_end):
 def set_firewall_addressgroup_rangeadd(hostname, group_name, address_start, address_end):
     address = str(address_start) + "-" + str(address_end)
     address = str(address_start) + "-" + str(address_end)
     cmd = {"op": "set", "path": ["firewall","group",'address-group', group_name, "address", address]}
     cmd = {"op": "set", "path": ["firewall","group",'address-group', group_name, "address", address]}

+ 191 - 0
vycontrol/vyos2.py

@@ -0,0 +1,191 @@
+import requests
+import json
+import pprint
+import sys
+import logging
+#logger = logging.getLogger(__name__)
+
+
+from config.models import Instance
+from django.contrib.auth.models import Group
+from django.contrib.auth.models import User
+
+import perms
+
+class vyapi:
+    error =     None
+    success =   None
+    result =    None
+    data =      None
+    reason =    None
+    def __init__(self, result, data = None, reason=None):
+
+        if result == True:
+            self.success = True
+        else:
+            self.error = True
+        self.result = result
+        self.data = data
+        self.reason = reason
+
+
+def log(area, value = [], end = True):
+    print("\n\n")
+    print("######################## START LOG " + area.upper())
+    pprint.pprint(value, indent=4, width=160) 
+
+    if end == True:
+        print("######################## END LOG " + area.upper())
+    print("\n\n")
+
+
+log("api " + " !!!!!!!!!!!!!! START NEW WEB PROCESS", end=False)
+
+API_LIST = {}
+API_LIST["get"] = {}
+API_LIST["get"]["description"]              = 'Show config'
+API_LIST["get"]["path"]                     = 'retrieve'
+API_LIST["get"]["op"] = {}
+API_LIST["get"]["op"]["showConfig"]         = 'path'
+
+API_LIST["post"] = {}
+API_LIST["post"]["description"]              = 'Configuration mode requests'
+API_LIST["post"]["path"]                     = "configure"
+API_LIST["post"]["op"] = {}
+API_LIST["post"]["op"]["set"]                = 'path'
+API_LIST["post"]["op"]["delete"]             = 'path'
+API_LIST["post"]["op"]["comment"]            = 'path'
+
+API_LIST["conf"] = {}
+API_LIST["conf"]["description"]              = 'Configuration management requests'
+API_LIST["conf"]["path"]                     = 'config-file'
+API_LIST["conf"]["op"] = {}
+API_LIST["conf"]["op"]["save"]               = 'file'
+API_LIST["conf"]["op"]["load"]               = 'file'
+
+API_LIST["op-generate"] = {}
+API_LIST["op-generate"]["description"]       = 'Operational mode commands - generate'
+API_LIST["op-generate"]["path"]              = 'generate'
+API_LIST["op-generate"]["op"] = {}
+API_LIST["op-generate"]["op"]["generate"]    = 'path'
+
+API_LIST["op-show"] = {}
+API_LIST["op-show"]["description"]           = 'Operational mode commands - show'
+API_LIST["op-show"]["path"]                  = 'show'
+API_LIST["op-show"]["op"] = {}
+API_LIST["op-show"]["op"]["show"]            = 'path'
+
+
+def get_key(hostname):
+    # permcheck
+    instance = Instance.objects.get(hostname=hostname)
+    return instance.key
+
+def get_api_data(hostname, api, op, cmd):
+    instance = Instance.objects.get(hostname=hostname)
+
+    if instance.https == True:
+        protocol = "https"
+    else:
+        protocol = "http"
+
+    if instance.port == None:
+        instance.port = 443
+
+    api_exists = False
+    if (    api in API_LIST 
+        and 'op' in API_LIST[api]
+        and op in API_LIST[api]['op']
+    ):
+        api_exists =        True
+        api_op =            op
+        api_path =          API_LIST[api]['path']
+        api_subcommand =    API_LIST[api]['op'][op]
+    else:
+        return False
+
+    if api_exists == False:
+        return False
+    else:
+        #log("api_path ", api_path)
+        #log("protocol ", protocol)
+        #log("instance.hostname ", instance.hostname)
+        #log("instance.port ", instance.port)
+        api_url = protocol + "://" + instance.hostname + ":" + str(instance.port) + "/" + api_path
+        api_data = {
+            'api_url':          api_url,
+            'api_op':           api_op,
+            'api_subcommand':   api_subcommand
+        }
+        log("api call", api_data)
+        return api_data
+
+
+def api(hostname, api, op, cmd, description = ""):
+    api_data = get_api_data(hostname=hostname, api=api, op=op, cmd=cmd)
+
+    if api_data == False:
+        v = vyapi(result = False)
+        return v
+
+    cmd = {
+        "op":                           api_data['api_op'],
+        api_data['api_subcommand'] :    cmd
+    }
+     
+    post = {'key': get_key(hostname), 'data': json.dumps(cmd)}
+    log("api " +  api_data['api_subcommand'], post)
+
+
+    post = {
+        'key':      get_key(hostname),
+        'data':     json.dumps(cmd)
+    }
+
+    try:
+        resp = requests.post(api_data['api_url'], verify=False, data=post, timeout=10)
+    except requests.exceptions.ConnectionError:
+        v = vyapi(result = False, reason= {
+            'exception'     : 'requests.exceptions.ConnectionError',
+            'respcode'      : resp.status_code
+        })
+        log("failed to post url", api_data['api_url'])
+
+        return v
+
+
+
+    try:
+        respjson = resp.json()
+    except json.JSONDecodeError:
+        respjson = {'success': False, 'error': None, 'data': None}
+
+    v = vyapi(
+        result =    respjson['success'],
+        reason =    respjson['error'],
+        data =      respjson['data']
+    )   
+
+    log("api resp", [v.result, v.reason, v.data])
+
+
+
+
+    log_vars = {
+        'api_url':      api_data['api_url'],
+        'api_op':       api_data['api_op'],
+        'api_cmd':      cmd,
+        'resp_obj':     resp,
+        'resp_code':    resp.status_code,
+        'resp_result':  v.result,
+        'resp_reason':  v.reason,
+        'resp_data':    v.data
+    }
+
+    log("api " + description, log_vars)
+
+    return v
+
+    
+
+

+ 31 - 0
vycontrol/vyos_common.py

@@ -0,0 +1,31 @@
+import requests
+import json
+import pprint
+import sys
+import logging
+import vyos2
+
+import perms
+
+
+
+def get_firewall_rulenumber(hostname, firewall, rulenumber):
+    v = vyos2.api (
+        hostname=   hostname,
+        api =       "get",
+        op =        "showConfig",
+        cmd =       ["firewall", "name", firewall, "rule", rulenumber],
+        description = "get_firewall_rulenumber",
+    )
+    return v
+
+
+def get_firewall_group(hostname):
+    v = vyos2.api (
+        hostname=   hostname,
+        api =       "get",
+        op =        "showConfig",
+        cmd =       ["firewall", "group"],
+        description = "get_firewall_group",
+    )
+    return v

部分文件因为文件数量过多而无法显示