Merge remote-tracking branch 'qubesos/pr/45'

* qubesos/pr/45:
  Firewall settings
This commit is contained in:
Marek Marczykowski-Górecki 2017-10-21 01:38:20 +02:00
commit d165bd33b6
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
4 changed files with 385 additions and 362 deletions

View File

@ -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):
def get_column_string(self, col, rule):
# Address
if col == 0:
if rule.dsthost is None:
raise FirewallModifiedOutsideError('no dsthost')
d = {}
if not rule.proto:
d['proto'] = 'any'
d['portBegin'] = 'any'
d['portEnd'] = None
return "*"
else:
d['proto'] = rule.proto
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)
return "any"
elif rule.dstports.range[0] != rule.dstports.range[1]:
return str(rule.dstports)
else:
raise FirewallModifiedOutsideError(
'cannot map dsthost.type={!s}'.format(rule.dsthost))
return self.get_service_name(rule.dstports)
if rule.expire is not None:
d['expire'] = int(rule.expire)
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
rule = reversed_rules.pop(0)
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')
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 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.')
conf['allow'] = (common_action == 'accept')
if not allowIcmp and not conf['allow']:
raise FirewallModifiedOutsideError('ICMP must be allowed.')
if not allowDns and not conf['allow']:
raise FirewallModifiedOutsideError('DNS must be allowed')
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
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')
rules = []
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']))))
rules.append(rule)
netmask = str(rule['netmask']) if rule['netmask'] != 32 else None
rules.append(qubesadmin.firewall.Rule(None,
action=common_action,
dsthost='/'.join(map(str, filter((lambda x: x),
(rule['address'], netmask)))),
**kwargs))
if conf['allowDns']:
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) \

View File

@ -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()
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:
@ -757,114 +759,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):
selected = self.rulesTreeView.selectedIndexes()
if len(selected) > 0:
dialog = NewFwRuleDlg()
dialog.set_ok_enabled(True)
selected = self.rulesTreeView.selectedIndexes()
if len(selected) > 0:
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>

View File

@ -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,6 +64,31 @@
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QRadioButton" name="any_radio">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>71</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string/>
</property>
<property name="text">
<string> Any </string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QComboBox" name="addressComboBox">
<property name="editable">
@ -66,6 +96,13 @@
</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="2" column="1">
<widget class="QRadioButton" name="tcp_radio">
<property name="sizePolicy">
@ -85,44 +122,10 @@
</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>
</property>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>UDP</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QRadioButton" name="any_radio">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>71</width>
<height>0</height>
</size>
</property>
<property name="text">
<string> Any </string>
</property>
<property name="checked">
<bool>true</bool>
<string>Protocol</string>
</property>
</widget>
</item>

View File

@ -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">
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QRadioButton" name="policyAllowRadioButton">
<property name="text">
<string>Allow network access except...</string>
<string>Allow all outgoing Internet connections</string>
</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>
<widget class="QRadioButton" name="policyDenyRadioButton">
<property name="text">
<string>Allow ICMP traffic</string>
<string>Limit outgoing Internet connections to ...</string>
</property>
<property name="checked">
</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="7" column="0" colspan="2">
<widget class="QLabel" name="label_22">
<property name="text">
<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="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="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="QCheckBox" name="dnsCheckBox">
<property name="text">
<string>Allow DNS queries</string>
<widget class="QSpinBox" name="tempFullAccessTime">
<property name="suffix">
<string> min</string>
</property>
<property name="checked">
<bool>true</bool>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<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="5" column="0" colspan="2">
<layout class="QHBoxLayout" name="firewallRulesLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
@ -805,48 +858,57 @@
</item>
</layout>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="yumproxyCheckBox">
<property name="text">
<string>Allow connections to Updates Proxy</string>
</property>
</widget>
</item>
<item row="2" 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="0" column="0">
<widget class="QCheckBox" name="tempFullAccess">
<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>
<property name="font">
<font>
<weight>75</weight>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Allow full access for </string>
<string>Firewall has been modified manually - please use qvm-firewall for any further configuration.</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>
</widget>
<widget class="QWidget" name="devices_tab">
@ -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>