Explorar el Código

Firewall settings

Modified VM Settings - Firewall tab to be easier to use and saner.
Marta Marczykowska-Górecka hace 6 años
padre
commit
dd990c04ac
Se han modificado 4 ficheros con 366 adiciones y 343 borrados
  1. 158 141
      qubesmanager/firewall.py
  2. 37 91
      qubesmanager/settings.py
  3. 45 42
      ui/newfwruledlg.ui
  4. 126 69
      ui/settingsdlg.ui

+ 158 - 141
qubesmanager/firewall.py

@@ -143,17 +143,6 @@ class QubesFirewallRulesModel(QAbstractItemModel):
     def __init__(self, parent=None):
         QAbstractItemModel.__init__(self, parent)
 
-        self.__columnValues = {
-            0: lambda x: "*" if self.children[x]["address"] == "0.0.0.0" and
-                                self.children[x]["netmask"] == 0  else
-            self.children[x]["address"] + ("" if self.children[x][ "netmask"] == 32  else
-                                           " /{0}".format(self.children[x][
-                                               "netmask"])),
-            1: lambda x: "any" if self.children[x]["portBegin"] == 0  else
-            "{0}-{1}".format(self.children[x]["portBegin"], self.children[x][
-                "portEnd"]) if self.children[x]["portEnd"] is not None  else \
-                self.get_service_name(self.children[x]["portBegin"]),
-            2: lambda x: self.children[x]["proto"], }
         self.__columnNames = {0: "Address", 1: "Service", 2: "Protocol", }
         self.__services = list()
         pattern = re.compile("(?P<name>[a-z][a-z0-9-]+)\s+(?P<port>[0-9]+)/(?P<protocol>[a-z]+)", re.IGNORECASE)
@@ -171,23 +160,17 @@ class QubesFirewallRulesModel(QAbstractItemModel):
         from operator import attrgetter
 
         rev = (order == Qt.AscendingOrder)
-        if idx==0:
-            self.children.sort(key=lambda x: x['address'], reverse = rev)
-        if idx==1:
-            self.children.sort(key=lambda x: self.get_service_name(x[
-                "portBegin"]) if x["portEnd"] == None else x["portBegin"],
-                               reverse = rev)
-        if idx==2:
-            self.children.sort(key=lambda x: x['proto'], reverse
-            = rev)
+        self.children.sort(key = lambda x: self.get_column_string(idx, x)
+                           , reverse = rev)
+
         index1 = self.createIndex(0, 0)
-        index2 = self.createIndex(len(self)-1, len(self.__columnValues)-1)
+        index2 = self.createIndex(len(self)-1, len(self.__columnNames)-1)
         self.dataChanged.emit(index1, index2)
 
 
     def get_service_name(self, port):
         for service in self.__services:
-            if service[1] == port:
+            if str(service[1]) == str(port):
                 return service[0]
         return str(port)
 
@@ -197,129 +180,122 @@ class QubesFirewallRulesModel(QAbstractItemModel):
                 return service[1]
         return None
 
-    def get_column_string(self, col, row):
-        return self.__columnValues[col](row)
-
-
-    def rule_to_dict(self, rule):
-        if rule.dsthost is None:
-            raise FirewallModifiedOutsideError('no dsthost')
-
-        d = {}
-
-        if not rule.proto:
-            d['proto'] = 'any'
-            d['portBegin'] = 'any'
-            d['portEnd'] = None
-
-        else:
-            d['proto'] = rule.proto
+    def get_column_string(self, col, rule):
+        # Address
+        if col == 0:
+            if rule.dsthost is None:
+                return "*"
+            else:
+                if rule.dsthost.type == 'dst4'\
+                        and rule.dsthost.prefixlen == '32':
+                    return str(rule.dsthost)[:-3]
+                elif rule.dsthost.type == 'dst6'\
+                        and rule.dsthost.prefixlen == '128':
+                    return str(rule.dsthost)[:-4]
+                else:
+                    return str(rule.dsthost)
+
+        # Service
+        if col == 1:
             if rule.dstports is None:
-                raise FirewallModifiedOutsideError('no dstport')
-            d['portBegin'] = rule.dstports.range[0]
-            d['portEnd'] = rule.dstports.range[1] \
-                if rule.dstports.range[0] != rule.dstports.range[1] \
-                else None
-
-        if rule.dsthost.type == 'dsthost':
-            d['address'] = str(rule.dsthost)
-            d['netmask'] = 32
-        elif rule.dsthost.type == 'dst4':
-            network = ipaddress.IPv4Network(rule.dsthost)
-            d['address'] = str(network.network_address)
-            d['netmask'] = int(network.prefixlen)
-        else:
-            raise FirewallModifiedOutsideError(
-                'cannot map dsthost.type={!s}'.format(rule.dsthost))
-
-        if rule.expire is not None:
-            d['expire'] = int(rule.expire)
+                return "any"
+            elif rule.dstports.range[0] != rule.dstports.range[1]:
+                return str(rule.dstports)
+            else:
+                return self.get_service_name(rule.dstports)
 
-        return d
+        # Protocol
+        if col == 2:
+            if rule.proto is None:
+                return "any"
+            else:
+                return str(rule.proto)
+        return "unknown"
 
     def get_firewall_conf(self, vm):
         conf = {
             'allow': None,
-            'allowDns': False,
-            'allowIcmp': False,
-            'allowYumProxy': False,
+            'expire': 0,
             'rules': [],
         }
 
+        allowDns = False
+        allowIcmp = False
         common_action = None
-        tentative_action = None
 
         reversed_rules = list(reversed(vm.firewall.rules))
+        last_rule = reversed_rules.pop(0)
 
+        if last_rule == qubesadmin.firewall.Rule('action=accept') \
+                or last_rule == qubesadmin.firewall.Rule('action=drop'):
+            common_action = last_rule.action
+        else:
+            FirewallModifiedOutsideError('Last rule must be either '
+                                         'drop all or accept all.')
+
+        dns_rule = qubesadmin.firewall.Rule(None,
+                                        action='accept', specialtarget='dns')
+        icmp_rule = qubesadmin.firewall.Rule(None,
+                                        action='accept', proto='icmp')
         while reversed_rules:
-            rule = reversed_rules[0]
-            if rule.dsthost is not None or rule.proto is not None:
-                break
-            tentative_action = reversed_rules.pop(0).action
-
-        if not reversed_rules:
-            conf['allow'] = tentative_action == 'accept'
-            return conf
-
-        for rule in reversed_rules:
-            if rule.specialtarget == 'dns':
-                conf['allowDns'] = (rule.action == 'accept')
+            rule = reversed_rules.pop(0)
+
+            if rule == dns_rule:
+                allowDns = True
                 continue
 
-            if rule.proto == 'icmp':
-                if rule.icmptype is not None:
-                    raise FirewallModifiedOutsideError(
-                        'cannot map icmptype != None')
-                conf['allowIcmp'] = (rule.action == 'accept')
+            if rule.proto == icmp_rule:
+                allowIcmp = True
                 continue
 
-            if common_action is None:
-                common_action = rule.action
-            elif common_action != rule.action:
-                raise FirewallModifiedOutsideError('incoherent action')
+            if rule.specialtarget is not None or rule.icmptype is not None:
+                raise FirewallModifiedOutsideError("Rule type unknown!")
 
-            conf['rules'].insert(0, self.rule_to_dict(rule))
+            if (rule.dsthost is not None or rule.proto is not None) \
+                    and rule.expire is None:
+                if rule.action == 'accept':
+                    conf['rules'].insert(0, rule)
+                    continue
+                else:
+                    raise FirewallModifiedOutsideError('No blacklist support.')
 
-        if common_action is None or common_action != tentative_action:
-            # we've got only specialtarget and/or icmp
-            conf['allow'] = tentative_action == 'accept'
-            return conf
+            if rule.expire is not None and rule.dsthost is None \
+                    and rule.proto is None:
+                conf['expire'] = int(str(rule.expire))
+                continue
 
-        raise FirewallModifiedOutsideError('it does not add up')
+            raise FirewallModifiedOutsideError('it does not add up.')
 
-    def write_firewall_conf(self, vm, conf):
-        common_action = qubesadmin.firewall.Action(
-            'drop' if conf['allow'] else 'accept')
+        conf['allow'] = (common_action == 'accept')
 
-        rules = []
+        if not allowIcmp and not conf['allow']:
+            raise FirewallModifiedOutsideError('ICMP must be allowed.')
 
-        for rule in conf['rules']:
-            kwargs = {}
-            if rule['proto'] != 'any':
-                kwargs['proto'] = rule['proto']
-                if rule['portBegin'] != 'any':
-                    kwargs['dstports'] = '-'.join(map(str, filter((lambda x: x),
-                        (rule['portBegin'], rule['portEnd']))))
+        if not allowDns and not conf['allow']:
+            raise FirewallModifiedOutsideError('DNS must be allowed')
 
-            netmask = str(rule['netmask']) if rule['netmask'] != 32 else None
+        return conf
 
-            rules.append(qubesadmin.firewall.Rule(None,
-                action=common_action,
-                dsthost='/'.join(map(str, filter((lambda x: x),
-                    (rule['address'], netmask)))),
-                **kwargs))
+    def write_firewall_conf(self, vm, conf):
+        rules = []
 
-        if conf['allowDns']:
+        for rule in conf['rules']:
+            rules.append(rule)
+
+        if not conf['allow']:
             rules.append(qubesadmin.firewall.Rule(None,
                 action='accept', specialtarget='dns'))
 
-        if conf['allowIcmp']:
+        if not conf['allow']:
             rules.append(qubesadmin.firewall.Rule(None,
                 action='accept', proto='icmp'))
 
-        if common_action == 'drop':
+        if conf['allow']:
             rules.append(qubesadmin.firewall.Rule(None,
                 action='accept'))
+        else:
+            rules.append(qubesadmin.firewall.Rule(None,
+                action = 'drop'))
 
         vm.firewall.rules = rules
 
@@ -331,58 +307,98 @@ class QubesFirewallRulesModel(QAbstractItemModel):
         conf = self.get_firewall_conf(vm)
 
         self.allow = conf["allow"]
-        self.allowDns = conf["allowDns"]
-        self.allowIcmp = conf["allowIcmp"]
-        self.allowYumProxy = conf["allowYumProxy"]
-        self.tempFullAccessExpireTime = 0
+
+        self.tempFullAccessExpireTime = conf['expire']
 
         for rule in conf["rules"]:
             self.appendChild(rule)
-            if "expire" in rule and rule["address"] == "0.0.0.0":
-                self.tempFullAccessExpireTime = rule["expire"]
 
     def get_vm_name(self):
         return self.__vm.name
 
-    def apply_rules(self, allow, dns, icmp, yumproxy, tempFullAccess=False,
+    def apply_rules(self, allow, tempFullAccess=False,
                     tempFullAccessTime=None):
         assert self.__vm is not None
 
-        if self.allow != allow or self.allowDns != dns or \
-                self.allowIcmp != icmp or self.allowYumProxy != yumproxy or \
+        if self.allow != allow or \
                 (self.tempFullAccessExpireTime != 0) != tempFullAccess:
             self.fw_changed = True
 
         conf = { "allow": allow,
-                "allowDns": dns,
-                "allowIcmp": icmp,
-                "allowYumProxy": yumproxy,
                 "rules": list()
             }
 
-        for rule in self.children:
-            if "expire" in rule and rule["address"] == "0.0.0.0" and \
-                    rule["netmask"] == 0 and rule["proto"] == "any":
-                # rule already present, update its time
-                if tempFullAccess:
-                    rule["expire"] = \
-                        int(datetime.datetime.now().strftime("%s")) + \
-                        tempFullAccessTime*60
-                tempFullAccess = False
-            conf["rules"].append(rule)
+        conf['rules'].extend(self.children)
 
         if tempFullAccess and not allow:
-            conf["rules"].append({"address": "0.0.0.0",
-                                  "netmask": 0,
-                                  "proto": "any",
-                                  "expire": int(
-                                      datetime.datetime.now().strftime("%s"))+\
-                                        tempFullAccessTime*60
-                                  })
+            conf["rules"].append(qubesadmin.firewall.Rule(None,action='accept'
+                        , expire=int(datetime.datetime.now().strftime("%s"))+\
+                                        tempFullAccessTime*60))
 
         if self.fw_changed:
             self.write_firewall_conf(self.__vm, conf)
 
+    def populate_edit_dialog(self, dialog, row):
+        address = self.get_column_string(0, self.children[row])
+        dialog.addressComboBox.setItemText(0, address)
+        dialog.addressComboBox.setCurrentIndex(0)
+        service = self.get_column_string(1, self.children[row])
+        if service == "any":
+            service = ""
+        dialog.serviceComboBox.setItemText(0, service)
+        dialog.serviceComboBox.setCurrentIndex(0)
+        protocol = self.get_column_string(2, self.children[row])
+        if protocol == "tcp":
+            dialog.tcp_radio.setChecked(True)
+        elif protocol == "udp":
+            dialog.udp_radio.setChecked(True)
+        else:
+            dialog.any_radio.setChecked(True)
+
+    def run_rule_dialog(self, dialog, row = None):
+        if dialog.exec_():
+
+            address = str(dialog.addressComboBox.currentText())
+            service = str(dialog.serviceComboBox.currentText())
+
+            rule = qubesadmin.firewall.Rule(None,action='accept')
+
+            if address is not None and address != "*":
+                try:
+                    rule.dsthost = address
+                except ValueError:
+                    QMessageBox.warning(None, self.tr("Invalid address"),
+                        self.tr("Address '{0}' is invalid.").format(address))
+
+            if dialog.tcp_radio.isChecked():
+                rule.proto = 'tcp'
+            elif dialog.udp_radio.isChecked():
+                rule.proto = 'udp'
+
+            if '-' in service:
+                try:
+                    rule.dstports = service
+                except ValueError:
+                    QMessageBox.warning(None, self.tr("Invalid port or service"),
+                        self.tr("Port number or service '{0}' is invalid.")
+                                        .format(service))
+            elif service is not None:
+                try:
+                    rule.dstports = service
+                except (TypeError, ValueError) as ex:
+                    if self.get_service_port(service) is not None:
+                        rule.dstports = self.get_service_port(service)
+                    else:
+                        QMessageBox.warning(None,
+                            self.tr("Invalid port or service"),
+                            self.tr("Port number or service '{0}' is invalid.")
+                                            .format(service))
+
+            if row is not None:
+                self.setChild(row, rule)
+            else:
+                self.appendChild(rule)
+
     def index(self, row, column, parent=QModelIndex()):
         if not self.hasIndex(row, column, parent):
             return QModelIndex()
@@ -396,7 +412,7 @@ class QubesFirewallRulesModel(QAbstractItemModel):
         return len(self)
 
     def columnCount(self, parent=QModelIndex()):
-        return len(self.__columnValues)
+        return len(self.__columnNames)
 
     def hasChildren(self, index=QModelIndex()):
         parentItem = index.internalPointer()
@@ -407,7 +423,8 @@ class QubesFirewallRulesModel(QAbstractItemModel):
 
     def data(self, index, role=Qt.DisplayRole):
         if index.isValid() and role == Qt.DisplayRole:
-            return self.__columnValues[index.column()](index.row())
+            return self.get_column_string(index.column()
+                                          ,self.children[index.row()])
 
     def headerData(self, section, orientation, role=Qt.DisplayRole):
         if section < len(self.__columnNames) \

+ 37 - 91
qubesmanager/settings.py

@@ -80,7 +80,8 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
 
         self.tabWidget.currentChanged.connect(self.current_tab_changed)
 
-#       self.tabWidget.setTabEnabled(self.tabs_indices["firewall"], vm.is_networked() and not vm.provides_network)
+        self.tabWidget.setTabEnabled(self.tabs_indices["firewall"],
+                            vm.netvm is not None and not vm.provides_network)
 
         ###### basic tab
         self.__init_basic_tab__()
@@ -96,8 +97,12 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
         ###### firewall tab
         if self.tabWidget.isTabEnabled(self.tabs_indices['firewall']):
             model = QubesFirewallRulesModel()
-            model.set_vm(vm)
-            self.set_fw_model(model)
+            try:
+                model.set_vm(vm)
+                self.set_fw_model(model)
+                self.firewallModifiedOutsidelabel.setVisible(False)
+            except FirewallModifiedOutsideError as ex:
+                self.disable_all_fw_conf()
 
             self.newRuleButton.clicked.connect(self.new_rule_button_pressed)
             self.editRuleButton.clicked.connect(self.edit_rule_button_pressed)
@@ -175,11 +180,8 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
             ret.append(self.tr('Error while saving changes: ') + str(ex))
 
         try:
-            if self.tabWidget.isTabEnabled(self.tabs_indices["firewall"]):
+            if self.policyAllowRadioButton.isEnabled():
                 self.fw_model.apply_rules(self.policyAllowRadioButton.isChecked(),
-                        self.dnsCheckBox.isChecked(),
-                        self.icmpCheckBox.isChecked(),
-                        self.yumproxyCheckBox.isChecked(),
                         self.tempFullAccess.isChecked(),
                         self.tempFullAccessTime.value())
                 if self.fw_model.fw_changed:
@@ -773,114 +775,58 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
         self.rulesTreeView.header().setResizeMode(QHeaderView.ResizeToContents)
         self.rulesTreeView.header().setResizeMode(0, QHeaderView.Stretch)
         self.set_allow(model.allow)
-        self.dnsCheckBox.setChecked(model.allowDns)
-        self.icmpCheckBox.setChecked(model.allowIcmp)
-        self.yumproxyCheckBox.setChecked(model.allowYumProxy)
         if model.tempFullAccessExpireTime:
             self.tempFullAccess.setChecked(True)
             self.tempFullAccessTime.setValue(
                 (model.tempFullAccessExpireTime -
                 int(datetime.datetime.now().strftime("%s")))/60)
 
+    def disable_all_fw_conf(self):
+        self.firewallModifiedOutsidelabel.setVisible(True)
+        self.policyAllowRadioButton.setEnabled(False)
+        self.policyDenyRadioButton.setEnabled(False)
+        self.rulesTreeView.setEnabled(False)
+        self.newRuleButton.setEnabled(False)
+        self.editRuleButton.setEnabled(False)
+        self.deleteRuleButton.setEnabled(False)
+        self.firewalRulesLabel.setEnabled(False)
+        self.tempFullAccessWidget.setEnabled(False)
+
     def set_allow(self, allow):
         self.policyAllowRadioButton.setChecked(allow)
         self.policyDenyRadioButton.setChecked(not allow)
         self.policy_changed(allow)
 
     def policy_changed(self, checked):
-        self.tempFullAccessWidget.setEnabled(self.policyDenyRadioButton.isChecked())
+        self.rulesTreeView.setEnabled(self.policyDenyRadioButton.isChecked())
+        self.newRuleButton.setEnabled(self.policyDenyRadioButton.isChecked())
+        self.editRuleButton.setEnabled(self.policyDenyRadioButton.isChecked())
+        self.deleteRuleButton.setEnabled(self.policyDenyRadioButton.isChecked())
+        self.firewalRulesLabel.setEnabled(
+            self.policyDenyRadioButton.isChecked())
+        self.tempFullAccessWidget.setEnabled(
+            self.policyDenyRadioButton.isChecked())
 
     def new_rule_button_pressed(self):
         dialog = NewFwRuleDlg()
-        self.run_rule_dialog(dialog)
+        self.fw_model.run_rule_dialog(dialog)
 
     def edit_rule_button_pressed(self):
-        dialog = NewFwRuleDlg()
-        dialog.set_ok_enabled(True)
+
         selected = self.rulesTreeView.selectedIndexes()
+
         if len(selected) > 0:
+            dialog = NewFwRuleDlg()
+            dialog.set_ok_enabled(True)
             row = self.rulesTreeView.selectedIndexes().pop().row()
-            address = self.fw_model.get_column_string(0, row).replace(' ', '')
-            dialog.addressComboBox.setItemText(0, address)
-            dialog.addressComboBox.setCurrentIndex(0)
-            service = self.fw_model.get_column_string(1, row)
-            if service == "any":
-                service = ""
-            dialog.serviceComboBox.setItemText(0, service)
-            dialog.serviceComboBox.setCurrentIndex(0)
-            protocol = self.fw_model.get_column_string(2, row)
-            if protocol == "tcp":
-                dialog.tcp_radio.setChecked(True)
-            elif protocol == "udp":
-                dialog.udp_radio.setChecked(True)
-            else:
-                dialog.any_radio.setChecked(True)
-
-            self.run_rule_dialog(dialog, row)
+            self.fw_model.populate_edit_dialog(dialog, row)
+            self.fw_model.run_rule_dialog(dialog, row)
 
     def delete_rule_button_pressed(self):
-        for i in set([index.row() for index in self.rulesTreeView.selectedIndexes()]):
+        for i in set([index.row() for index
+                      in self.rulesTreeView.selectedIndexes()]):
             self.fw_model.removeChild(i)
 
-    def run_rule_dialog(self, dialog, row = None):
-        if dialog.exec_():
-            address = str(dialog.addressComboBox.currentText())
-            service = str(dialog.serviceComboBox.currentText())
-            port = None
-            port2 = None
-
-            unmask = address.split("/", 1)
-            if len(unmask) == 2:
-                address = unmask[0]
-                netmask = int(unmask[1])
-            else:
-                netmask = 32
-
-            if address == "*":
-                address = "0.0.0.0"
-                netmask = 0
-
-            if dialog.any_radio.isChecked():
-                protocol = "any"
-                port = 0
-            else:
-                if dialog.tcp_radio.isChecked():
-                    protocol = "tcp"
-                elif dialog.udp_radio.isChecked():
-                    protocol = "udp"
-                else:
-                    protocol = "any"
-
-                try:
-                    range = service.split("-", 1)
-                    if len(range) == 2:
-                        port = int(range[0])
-                        port2 = int(range[1])
-                    else:
-                        port = int(service)
-                except (TypeError, ValueError) as ex:
-                    port = self.fw_model.get_service_port(service)
-
-            if port is not None:
-                if port2 is not None and port2 <= port:
-                    QMessageBox.warning(None, self.tr("Invalid service ports range"),
-                        self.tr("Port {0} is lower than port {1}.").format(
-                            port2, port))
-                else:
-                    item = {"address": address,
-                            "netmask": netmask,
-                            "portBegin": port,
-                            "portEnd": port2,
-                            "proto": protocol,
-                    }
-                    if row is not None:
-                        self.fw_model.setChild(row, item)
-                    else:
-                        self.fw_model.appendChild(item)
-            else:
-                QMessageBox.warning(None, self.tr("Invalid service name"),
-                    self.tr("Service '{0}' is unknown.").format(service))
-
 
 # Bases on the original code by:
 # Copyright (c) 2002-2007 Pascal Varet <p.varet@gmail.com>

+ 45 - 42
ui/newfwruledlg.ui

@@ -31,10 +31,22 @@
      <property name="verticalSpacing">
       <number>6</number>
      </property>
-     <item row="2" column="0">
-      <widget class="QLabel" name="label">
+     <item row="2" column="2">
+      <widget class="QRadioButton" name="udp_radio">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>0</width>
+         <height>0</height>
+        </size>
+       </property>
        <property name="text">
-        <string>Protocol</string>
+        <string>UDP</string>
        </property>
       </widget>
      </item>
@@ -45,13 +57,6 @@
        </property>
       </widget>
      </item>
-     <item row="1" column="1" colspan="3">
-      <widget class="QComboBox" name="serviceComboBox">
-       <property name="editable">
-        <bool>true</bool>
-       </property>
-      </widget>
-     </item>
      <item row="0" column="0">
       <widget class="QLabel" name="label_2">
        <property name="text">
@@ -59,15 +64,8 @@
        </property>
       </widget>
      </item>
-     <item row="0" column="1" colspan="3">
-      <widget class="QComboBox" name="addressComboBox">
-       <property name="editable">
-        <bool>true</bool>
-       </property>
-      </widget>
-     </item>
-     <item row="2" column="1">
-      <widget class="QRadioButton" name="tcp_radio">
+     <item row="2" column="3">
+      <widget class="QRadioButton" name="any_radio">
        <property name="sizePolicy">
         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
          <horstretch>0</horstretch>
@@ -76,36 +74,37 @@
        </property>
        <property name="minimumSize">
         <size>
-         <width>0</width>
+         <width>71</width>
          <height>0</height>
         </size>
        </property>
+       <property name="toolTip">
+        <string/>
+       </property>
        <property name="text">
-        <string>TCP</string>
+        <string> Any   </string>
+       </property>
+       <property name="checked">
+        <bool>true</bool>
        </property>
       </widget>
      </item>
-     <item row="2" column="2">
-      <widget class="QRadioButton" name="udp_radio">
-       <property name="sizePolicy">
-        <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-         <horstretch>0</horstretch>
-         <verstretch>0</verstretch>
-        </sizepolicy>
-       </property>
-       <property name="minimumSize">
-        <size>
-         <width>0</width>
-         <height>0</height>
-        </size>
+     <item row="0" column="1" colspan="3">
+      <widget class="QComboBox" name="addressComboBox">
+       <property name="editable">
+        <bool>true</bool>
        </property>
-       <property name="text">
-        <string>UDP</string>
+      </widget>
+     </item>
+     <item row="1" column="1" colspan="3">
+      <widget class="QComboBox" name="serviceComboBox">
+       <property name="editable">
+        <bool>true</bool>
        </property>
       </widget>
      </item>
-     <item row="2" column="3">
-      <widget class="QRadioButton" name="any_radio">
+     <item row="2" column="1">
+      <widget class="QRadioButton" name="tcp_radio">
        <property name="sizePolicy">
         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
          <horstretch>0</horstretch>
@@ -114,15 +113,19 @@
        </property>
        <property name="minimumSize">
         <size>
-         <width>71</width>
+         <width>0</width>
          <height>0</height>
         </size>
        </property>
        <property name="text">
-        <string> Any   </string>
+        <string>TCP</string>
        </property>
-       <property name="checked">
-        <bool>true</bool>
+      </widget>
+     </item>
+     <item row="2" column="0">
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Protocol</string>
        </property>
       </widget>
      </item>

+ 126 - 69
ui/settingsdlg.ui

@@ -29,7 +29,7 @@
         <locale language="English" country="UnitedStates"/>
        </property>
        <property name="currentIndex">
-        <number>1</number>
+        <number>2</number>
        </property>
        <widget class="QWidget" name="basic_tab">
         <property name="locale">
@@ -655,48 +655,101 @@
          <string>Firewall rules</string>
         </attribute>
         <layout class="QGridLayout" name="gridLayout_8">
-         <item row="0" column="0">
-          <widget class="QRadioButton" name="policyAllowRadioButton">
-           <property name="text">
-            <string>Allow network access except...</string>
+         <item row="1" column="0">
+          <layout class="QHBoxLayout" name="horizontalLayout_5">
+           <item>
+            <widget class="QRadioButton" name="policyAllowRadioButton">
+             <property name="text">
+              <string>Allow all outgoing Internet connections</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QRadioButton" name="policyDenyRadioButton">
+             <property name="text">
+              <string>Limit outgoing Internet connections to ...</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+         <item row="3" column="0" colspan="2">
+          <widget class="Line" name="line">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
            </property>
           </widget>
          </item>
-         <item row="0" column="1">
-          <widget class="QCheckBox" name="icmpCheckBox">
-           <property name="minimumSize">
-            <size>
-             <width>323</width>
-             <height>0</height>
-            </size>
-           </property>
+         <item row="7" column="0" colspan="2">
+          <widget class="QLabel" name="label_22">
            <property name="text">
-            <string>Allow ICMP traffic</string>
+            <string>NOTE:  To block all network access, set Networking to (none) on the Basic settings tab. This tab provides a very simplified firewall configuration. All DNS requests and ICMP (pings) will be allowed. For more granular control, use the command line tool qvm-firewall.</string>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
            </property>
-           <property name="checked">
+           <property name="wordWrap">
             <bool>true</bool>
            </property>
           </widget>
          </item>
-         <item row="1" column="0">
-          <widget class="QRadioButton" name="policyDenyRadioButton">
+         <item row="4" column="0">
+          <widget class="QLabel" name="firewalRulesLabel">
            <property name="text">
-            <string>Deny network access except...</string>
+            <string>List of allowed (whitelisted) addresses:</string>
            </property>
           </widget>
          </item>
-         <item row="1" column="1">
-          <widget class="QCheckBox" name="dnsCheckBox">
-           <property name="text">
-            <string>Allow DNS queries</string>
-           </property>
-           <property name="checked">
+         <item row="6" column="0">
+          <widget class="QWidget" name="tempFullAccessWidget" native="true">
+           <property name="enabled">
             <bool>true</bool>
            </property>
+           <layout class="QGridLayout" name="gridLayout_6">
+            <property name="leftMargin">
+             <number>0</number>
+            </property>
+            <property name="topMargin">
+             <number>0</number>
+            </property>
+            <property name="bottomMargin">
+             <number>0</number>
+            </property>
+            <item row="1" column="0">
+             <widget class="QCheckBox" name="tempFullAccess">
+              <property name="text">
+               <string>Allow full access for </string>
+              </property>
+             </widget>
+            </item>
+            <item row="1" column="1">
+             <widget class="QSpinBox" name="tempFullAccessTime">
+              <property name="suffix">
+               <string> min</string>
+              </property>
+              <property name="value">
+               <number>5</number>
+              </property>
+             </widget>
+            </item>
+            <item row="1" column="2">
+             <spacer name="horizontalSpacer_2">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+           </layout>
           </widget>
          </item>
-         <item row="3" column="0" colspan="2">
-          <layout class="QHBoxLayout" name="horizontalLayout_2">
+         <item row="5" column="0" colspan="2">
+          <layout class="QHBoxLayout" name="firewallRulesLayout">
            <property name="sizeConstraint">
             <enum>QLayout::SetMaximumSize</enum>
            </property>
@@ -805,46 +858,55 @@
            </item>
           </layout>
          </item>
-         <item row="2" column="1">
-          <widget class="QCheckBox" name="yumproxyCheckBox">
-           <property name="text">
-            <string>Allow connections to Updates Proxy</string>
+         <item row="0" column="0">
+          <widget class="QLabel" name="firewallModifiedOutsidelabel">
+           <property name="palette">
+            <palette>
+             <active>
+              <colorrole role="WindowText">
+               <brush brushstyle="SolidPattern">
+                <color alpha="255">
+                 <red>255</red>
+                 <green>0</green>
+                 <blue>0</blue>
+                </color>
+               </brush>
+              </colorrole>
+             </active>
+             <inactive>
+              <colorrole role="WindowText">
+               <brush brushstyle="SolidPattern">
+                <color alpha="255">
+                 <red>255</red>
+                 <green>0</green>
+                 <blue>0</blue>
+                </color>
+               </brush>
+              </colorrole>
+             </inactive>
+             <disabled>
+              <colorrole role="WindowText">
+               <brush brushstyle="SolidPattern">
+                <color alpha="255">
+                 <red>139</red>
+                 <green>142</green>
+                 <blue>142</blue>
+                </color>
+               </brush>
+              </colorrole>
+             </disabled>
+            </palette>
            </property>
-          </widget>
-         </item>
-         <item row="2" column="0">
-          <widget class="QWidget" name="tempFullAccessWidget" native="true">
-           <property name="enabled">
-            <bool>true</bool>
+           <property name="font">
+            <font>
+             <weight>75</weight>
+             <italic>true</italic>
+             <bold>true</bold>
+            </font>
+           </property>
+           <property name="text">
+            <string>Firewall has been modified manually - please use qvm-firewall for any further configuration.</string>
            </property>
-           <layout class="QGridLayout" name="gridLayout_6">
-            <property name="leftMargin">
-             <number>0</number>
-            </property>
-            <property name="topMargin">
-             <number>0</number>
-            </property>
-            <property name="bottomMargin">
-             <number>0</number>
-            </property>
-            <item row="0" column="0">
-             <widget class="QCheckBox" name="tempFullAccess">
-              <property name="text">
-               <string>Allow full access for </string>
-              </property>
-             </widget>
-            </item>
-            <item row="0" column="1">
-             <widget class="QSpinBox" name="tempFullAccessTime">
-              <property name="suffix">
-               <string> min</string>
-              </property>
-              <property name="value">
-               <number>5</number>
-              </property>
-             </widget>
-            </item>
-           </layout>
           </widget>
          </item>
         </layout>
@@ -1035,11 +1097,6 @@
   <tabstop>vcpus</tabstop>
   <tabstop>include_in_balancing</tabstop>
   <tabstop>kernel</tabstop>
-  <tabstop>policyAllowRadioButton</tabstop>
-  <tabstop>policyDenyRadioButton</tabstop>
-  <tabstop>icmpCheckBox</tabstop>
-  <tabstop>dnsCheckBox</tabstop>
-  <tabstop>yumproxyCheckBox</tabstop>
   <tabstop>newRuleButton</tabstop>
   <tabstop>rulesTreeView</tabstop>
   <tabstop>editRuleButton</tabstop>