├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── build.yml ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── INSTALL ├── LICENSE ├── README.md ├── debian ├── README.Debian ├── README.source ├── changelog ├── compat ├── control ├── copyright ├── rules └── source │ └── format ├── gh-build.sh ├── kcm ├── CMakeLists.txt ├── nomadfirewallkcm.cpp ├── nomadfirewallkcm.h ├── org_nxos_firewall.desktop ├── package │ ├── contents │ │ └── ui │ │ │ ├── ConnectionItemDelegate.qml │ │ │ ├── ConnectionsView.qml │ │ │ ├── GlobalRules.qml │ │ │ ├── LogItemDelegate.qml │ │ │ ├── LogsView.qml │ │ │ ├── RuleEdit.qml │ │ │ ├── RuleListItem.qml │ │ │ ├── RulesView.qml │ │ │ └── main.qml │ └── metadata.desktop └── version.h.cmake └── plugins ├── CMakeLists.txt ├── netstat ├── CMakeLists.txt ├── conectionsmodel.cpp ├── conectionsmodel.h ├── helper │ ├── CMakeLists.txt │ ├── netstathelper.cpp │ ├── netstathelper.h │ └── org.nxos.netstat.actions ├── netstatclient.cpp ├── netstatclient.h ├── netstatplugin.cpp ├── netstatplugin.h └── qmldir └── ufw ├── CMakeLists.txt ├── appprofiles.cpp ├── appprofiles.h ├── blocker.cpp ├── blocker.h ├── helper ├── CMakeLists.txt ├── defaults ├── helper.cpp ├── helper.h ├── kcm_ufw_helper.py.cmake ├── org.kde.ufw.service.cmake ├── org.nomad.ufw.actions └── ufw_helper_config.h.cmake ├── loglistmodel.cpp ├── loglistmodel.h ├── profile.cpp ├── profile.h ├── qmldir ├── rule.cpp ├── rule.h ├── rulelistmodel.cpp ├── rulelistmodel.h ├── rulewrapper.cpp ├── rulewrapper.h ├── types.cpp ├── types.h ├── ufwclient.cpp ├── ufwclient.h ├── ufwplugin.cpp └── ufwplugin.h /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Browser [e.g. chrome, safari] 26 | - Version [e.g. 22] 27 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build and push packages to PackageCloud. 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | paths-ignore: 8 | - 'README.md' 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - name: Install dependencies. 17 | run: | 18 | sudo gem install package_cloud 19 | 20 | - name: Build. 21 | run: | 22 | sudo ./gh-build.sh 23 | 24 | - name: Push package. 25 | env: 26 | PACKAGECLOUD_TOKEN: ${{ secrets.PACKAGECLOUD_TOKEN }} 27 | run: | 28 | package_cloud push nitrux/repo/debian/trixie files/*.deb 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | 3 | *.slo 4 | *.lo 5 | *.o 6 | *.a 7 | *.la 8 | *.lai 9 | *.so 10 | *.dll 11 | *.dylib 12 | 13 | # Qt-es 14 | 15 | /.qmake.cache 16 | /.qmake.stash 17 | *.pro.user 18 | *.pro.user.* 19 | *.qbs.user 20 | *.qbs.user.* 21 | *.moc 22 | moc_*.cpp 23 | moc_*.h 24 | qrc_*.cpp 25 | ui_*.h 26 | Makefile* 27 | *build-* 28 | 29 | # QtCreator 30 | 31 | *.autosave 32 | 33 | # QtCtreator Qml 34 | *.qmlproject.user 35 | *.qmlproject.user.* 36 | 37 | # QtCtreator CMake 38 | CMakeLists.txt.user* 39 | 40 | # VSCODE 41 | .vscode 42 | build -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: focal 2 | 3 | before_install: 4 | - gem install package_cloud 5 | 6 | script: 7 | - sudo ./travis-build.sh 8 | - package_cloud push nitrux/repo/debian/trixie *.deb 9 | 10 | branches: 11 | only: 12 | - master 13 | 14 | deploy: 15 | - provider: script 16 | script: wget -qO - https://raw.githubusercontent.com/Nitrux/nitrux-repository-util/master/upload-pkgs | sh -s *.deb 17 | skip_cleanup: true 18 | on: 19 | branch: master 20 | 21 | notifications: 22 | email: false 23 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.18.12) 2 | #----------------------------------------------------------------------------- 3 | # GENERAL CONFIGURATION 4 | #----------------------------------------------------------------------------- 5 | project(nomad-firewall) 6 | 7 | set(KF5_MIN_VERSION "5.30.0") 8 | set(QT_MIN_VERSION "5.7.0") 9 | 10 | #----------------------------------------------------------------------------- 11 | # DEPENDENCIES 12 | #----------------------------------------------------------------------------- 13 | # Python3 (search for this first so that we will not get Python2 by accident) 14 | find_package(PythonInterp 3 REQUIRED) 15 | 16 | # Qt5 17 | find_package(Qt5 REQUIRED COMPONENTS 18 | Core 19 | Qml 20 | ) 21 | 22 | # KDE5 23 | find_package(ECM REQUIRED NO_MODULE) 24 | set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) 25 | 26 | include(KDEInstallDirs) 27 | include(KDECompilerSettings) 28 | include(KDECMakeSettings) 29 | 30 | include(FeatureSummary) 31 | 32 | find_package(KF5 REQUIRED COMPONENTS 33 | CoreAddons 34 | KCMUtils 35 | I18n 36 | Plasma 37 | PlasmaQuick 38 | KDELibs4Support 39 | Declarative 40 | ) 41 | 42 | #----------------------------------------------------------------------------- 43 | # BUILD TYPES & FLAGS 44 | #----------------------------------------------------------------------------- 45 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -std=c++0x") 46 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g3 -O0") 47 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Werror -O2") 48 | 49 | #----------------------------------------------------------------------------- 50 | # SOURCES 51 | #----------------------------------------------------------------------------- 52 | add_subdirectory(plugins) 53 | add_subdirectory(kcm) 54 | 55 | #----------------------------------------------------------------------------- 56 | # BUILD SUMMARY 57 | #----------------------------------------------------------------------------- 58 | feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) 59 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | # (0) Minimum Requirements (tested, but might be lower) 2 | - Qt >= 5.7.0 3 | - KDE Workspace >= 5.8.0 4 | - Plasma Framework >= 5.32 5 | 6 | cd /path/to/src-dir/ 7 | mkdir build 8 | cd build 9 | cmake -DCMAKE_INSTALL_PREFIX=`kde4-config --prefix` -DCMAKE_BUILD_TYPE=Release -DLIB_INSTALL_DIR=lib -DKDE_INSTALL_USE_QT_SYS_PATHS=ON ../ 10 | make 11 | make install 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Firewall KCM [![Build Status](https://travis-ci.org/nx-desktop/nx-firewall.svg?branch=master)](https://travis-ci.org/nx-desktop/nx-firewall) 2 | 3 | This is the repository for the Plasma 5 Firewall KCM. 4 | 5 | # Requirements 6 | - CoreAddons. 7 | - KCMUtils. 8 | - I18n. 9 | - Plasma 5.8.4+. 10 | - PlasmaQuick. 11 | - KDELibs4Support. 12 | - Declarative. 13 | 14 | # Issues 15 | If you find problems with the contents of this repository please create an issue. 16 | 17 | ©2018 Nitrux Latinoamericana S.C. 18 | -------------------------------------------------------------------------------- /debian/README.Debian: -------------------------------------------------------------------------------- 1 | nx-firewall for Debian 2 | ------------------------ 3 | 4 | 5 | 6 | -- Alexis L?pez Zubieta Tue, 27 Jun 2017 16:07:53 -0500 7 | -------------------------------------------------------------------------------- /debian/README.source: -------------------------------------------------------------------------------- 1 | nx-firewall for Debian 2 | ------------------------ 3 | 4 | 6 | 7 | 8 | 9 | -- Alexis L?pez Zubieta Tue, 27 Jun 2017 16:07:53 -0500 10 | 11 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | nx-firewall (0.4.2) nxos; urgency=medium 2 | 3 | * Change Python dependency. 4 | 5 | -- Uri Herrera Fri, 28 Jun 2020 19:23:00 -0500 6 | 7 | nx-firewall (0.4.1) nxos; urgency=medium 8 | 9 | * Update name. 10 | 11 | -- Uri Herrera Tue, 25 Jun 2019 18:03:00 -0500 12 | 13 | nx-firewall (0.4-6) nxos; urgency=medium 14 | 15 | * Adding netstat to the build depends 16 | 17 | -- Alexis Lopez Zubieta Fri, 29 Sep 2017 13:05:34 -0500 18 | 19 | nx-firewall (0.4-5) nxos; urgency=medium 20 | 21 | * Change window background to a opaque one. 22 | * Enable logs auto-refresh only when the log tab is openend. 23 | 24 | -- Alexis López Zubieta Mon, 31 Jul 2017 21:44:11 -0500 25 | 26 | nx-firewall (0.4-4) nxos; urgency=medium 27 | 28 | * Improve integration with plasma theme 29 | 30 | -- Alexis López Zubieta Sat, 29 Jul 2017 23:46:09 -0500 31 | 32 | nx-firewall (0.4-3) nxos; urgency=medium 33 | 34 | * Improve rules moving 35 | 36 | -- Alexis López Zubieta Mon, 24 Jul 2017 18:20:14 -0500 37 | 38 | nx-firewall (0.4-2) nxos; urgency=medium 39 | 40 | * Create rule from logs. 41 | 42 | -- Alexis López Zubieta Tue, 18 Jul 2017 18:42:43 -0500 43 | 44 | nx-firewall (0.4-1) nxos; urgency=medium 45 | 46 | * Displaying firewall logs 47 | 48 | -- Alexis López Zubieta Tue, 18 Jul 2017 14:33:25 -0500 49 | 50 | nx-firewall (0.3-2) nxos; urgency=medium 51 | 52 | * Patch segfault when opened with systemsettings5. 53 | 54 | -- Alexis López Zubieta Wed, 12 Jul 2017 16:32:07 -0500 55 | 56 | nx-firewall (0.3-1) nxos; urgency=medium 57 | 58 | * Connections visualization and rules generation from connections. 59 | 60 | -- Alexis López Zubieta Wed, 12 Jul 2017 13:48:42 -0500 61 | 62 | nx-firewall (0.2-2) nxos; urgency=medium 63 | 64 | * Using FrameSvgItem instead of Rectangle as backgrounds. 65 | 66 | -- Alexis López Zubieta Fri, 30 Jun 2017 14:00:28 -0500 67 | 68 | nx-firewall (0.2-1) nxos; urgency=medium 69 | 70 | * Transform standalone application into a KCM. 71 | 72 | -- Alexis López Zubieta Thu, 29 Jun 2017 19:41:41 -0500 73 | 74 | nx-firewall (0.1-1) nxos; urgency=medium 75 | 76 | * Initial release 77 | 78 | -- Alexis López Zubieta Tue, 27 Jun 2017 16:07:53 -0500 79 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: nx-firewall 2 | Section: kde 3 | Priority: optional 4 | Maintainer: Uri Herrera 5 | Build-Depends: debhelper (>=9), cmake, extra-cmake-modules, libkf5i18n-dev, libkf5plasma-dev, libkf5declarative-dev, qtdeclarative5-dev, qtbase5-dev, libqt5x11extras5-dev, libkf5archive-dev, libkf5newstuff-dev, libkf5auth-dev, libkf5config-dev, libkf5kio-dev, libkf5configwidgets-dev, libkf5kcmutils-dev, libkf5kdelibs4support-dev, netstat-nat 6 | Standards-Version: 3.9.6 7 | 8 | Package: nx-firewall 9 | Architecture: any 10 | Depends: ${shlibs:Depends}, ${misc:Depends}, python3:any (>= 3.3.2-2~), ufw, netstat-nat 11 | Description: NX Firewall - Protect your workstation! 12 | NX Firewall allows you to protect your workstation from 13 | network atacks and also to avoid your data to be exposed 14 | on the network by an imprudent application. 15 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: nx-firewall 3 | Source: 4 | 5 | Files: * 6 | Copyright: 7 | 8 | License: GPL-3.0+ 9 | 10 | Files: debian/* 11 | Copyright: 2017 Alexis L?pez Zubieta 12 | License: GPL-3.0+ 13 | 14 | License: GPL-3.0+ 15 | This program is free software: you can redistribute it and/or modify 16 | it under the terms of the GNU General Public License as published by 17 | the Free Software Foundation, either version 3 of the License, or 18 | (at your option) any later version. 19 | . 20 | This package is distributed in the hope that it will be useful, 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | GNU General Public License for more details. 24 | . 25 | You should have received a copy of the GNU General Public License 26 | along with this program. If not, see . 27 | . 28 | On Debian systems, the complete text of the GNU General 29 | Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". 30 | 31 | # Please also look if there are files or directories which have a 32 | # different copyright/license attached and list them here. 33 | # Please avoid picking licenses with terms that are more restrictive than the 34 | # packaged work, as it may make Debian's contributions unacceptable upstream. 35 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # See debhelper(7) (uncomment to enable) 3 | # output every command that modifies files on the build system. 4 | #export DH_VERBOSE = 1 5 | 6 | 7 | # see FEATURE AREAS in dpkg-buildflags(1) 8 | #export DEB_BUILD_MAINT_OPTIONS = hardening=+all 9 | 10 | # see ENVIRONMENT in dpkg-buildflags(1) 11 | # package maintainers to append CFLAGS 12 | #export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic 13 | # package maintainers to append LDFLAGS 14 | #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed 15 | 16 | 17 | %: 18 | dh $@ 19 | 20 | 21 | # dh_make generated override targets 22 | # This is example for Cmake (See https://bugs.debian.org/641051 ) 23 | #override_dh_auto_configure: 24 | # dh_auto_configure -- # -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) 25 | 26 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /gh-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | 5 | apt -qq update 6 | apt -qq -yy install equivs curl git wget gnupg2 7 | 8 | ### FIXME - the container mauikit/ubuntu-18.04-amd64 does have the neon repo but for some idiotic reason it isn't working here 9 | 10 | wget -qO /etc/apt/sources.list.d/neon-user-repo.list https://raw.githubusercontent.com/Nitrux/iso-tool/development/configs/files/sources.list.neon.user 11 | 12 | apt-key adv --keyserver keyserver.ubuntu.com --recv-keys \ 13 | 55751E5D > /dev/null 14 | 15 | apt -qq update 16 | 17 | ### Install Dependencies 18 | DEBIAN_FRONTEND=noninteractive apt -qq -yy install devscripts lintian build-essential automake autotools-dev 19 | mk-build-deps -i -t "apt-get --yes" -r 20 | 21 | ### Build Deb 22 | mkdir source 23 | mv ./* source/ # Hack for debuild 24 | cd source 25 | debuild -b -uc -us 26 | -------------------------------------------------------------------------------- /kcm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/version.h) 2 | 3 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 4 | 5 | set(kcm_SRCS 6 | nomadfirewallkcm.cpp 7 | ) 8 | 9 | add_library(org.nxos.firewall MODULE ${kcm_SRCS}) 10 | 11 | target_link_libraries(org.nxos.firewall 12 | Qt5::Quick 13 | KF5::CoreAddons 14 | KF5::Declarative 15 | KF5::I18n 16 | KF5::QuickAddons) 17 | 18 | 19 | kcoreaddons_desktop_to_json(org.nxos.firewall org_nxos_firewall.desktop SERVICE_TYPES kcmodule.desktop) 20 | 21 | #this desktop file is installed only for retrocompatibility with sycoca 22 | install(FILES org_nxos_firewall.desktop DESTINATION ${SERVICES_INSTALL_DIR}) 23 | install(TARGETS org.nxos.firewall DESTINATION ${PLUGIN_INSTALL_DIR}/kcms) 24 | 25 | kpackage_install_package(package org.nxos.firewall kcms) 26 | -------------------------------------------------------------------------------- /kcm/nomadfirewallkcm.cpp: -------------------------------------------------------------------------------- 1 | #include "nomadfirewallkcm.h" 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "version.h" 10 | 11 | K_PLUGIN_FACTORY_WITH_JSON(NomadFirewallKCMFactory, 12 | "org_nxos_firewall.json", 13 | registerPlugin(); ) 14 | 15 | K_EXPORT_PLUGIN(NomadFirewallKCMFactory("org.nxos.firewall" /* kcm name */, "org.nxos.firewall" /* catalog name */)) 16 | 17 | NomadFirewallKCM::NomadFirewallKCM(QObject *parent, const QVariantList &args) : 18 | KQuickAddons::ConfigModule(parent, args) 19 | { 20 | KAboutData* about = new KAboutData("org.nxos.firewall", i18n("Configure Firewall"), 21 | "0.1", QString(), KAboutLicense::GPL_V3); 22 | about->addAuthor(i18n("Alexis López Zubieta"), QString(), "azubieta90@gmail.com"); 23 | setAboutData(about); 24 | setButtons(Help | Apply | Default); 25 | } 26 | 27 | NomadFirewallKCM::~NomadFirewallKCM() 28 | { 29 | 30 | } 31 | 32 | #include "nomadfirewallkcm.moc" 33 | -------------------------------------------------------------------------------- /kcm/nomadfirewallkcm.h: -------------------------------------------------------------------------------- 1 | #ifndef NOMADFIREWALLKCM_H 2 | #define NOMADFIREWALLKCM_H 3 | 4 | 5 | #include 6 | 7 | class NomadFirewallKCM : public KQuickAddons::ConfigModule 8 | { 9 | Q_OBJECT 10 | public: 11 | explicit NomadFirewallKCM(QObject *parent, const QVariantList &args); 12 | 13 | ~NomadFirewallKCM(); 14 | 15 | }; 16 | 17 | #endif // NOMADFIREWALLKCM_H 18 | -------------------------------------------------------------------------------- /kcm/org_nxos_firewall.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Icon=security-high 3 | Exec=kcmshell5 org_nxos_firewall 4 | 5 | Type=Service 6 | X-KDE-ServiceTypes=KCModule 7 | X-KDE-Library=org.nxos.firewall 8 | X-KDE-ParentApp=kcontrol 9 | X-KDE-System-Settings-Parent-Category=network 10 | X-KDE-Weight=80 11 | X-DocPath=kcontrol5/org.nxos.firewall/index.html 12 | 13 | 14 | Name=NX Firewall 15 | Comment=NX Firewall - Secure your workstation! 16 | X-KDE-Keywords=firewall, network, security 17 | Categories=Qt;KDE;X-KDE-settings-looknfeel; 18 | -------------------------------------------------------------------------------- /kcm/package/contents/ui/ConnectionItemDelegate.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Alexis Lopes Zubeta 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | import QtQuick 2.0 22 | import QtQuick.Layouts 1.3 23 | 24 | import org.kde.plasma.core 2.0 as PlasmaCore 25 | import org.kde.plasma.components 2.0 as PlasmaComponents 26 | 27 | MouseArea { 28 | id: itemRoot 29 | height: 48 30 | anchors.left: parent.left 31 | anchors.right: parent.right 32 | 33 | hoverEnabled: true 34 | 35 | signal filterConnection(var protocol, var localAddress, var foreignAddres, var status) 36 | 37 | Rectangle { 38 | id: background 39 | anchors.fill: parent 40 | color: theme.highlightColor 41 | 42 | visible: itemRoot.containsMouse 43 | } 44 | 45 | RowLayout { 46 | id: layout 47 | anchors.top: parent.top 48 | anchors.bottom: parent.bottom 49 | anchors.left: parent.left 50 | 51 | PlasmaComponents.Label { 52 | Layout.leftMargin: 12 53 | Layout.preferredWidth: 60 54 | text: model.protocol 55 | } 56 | PlasmaComponents.Label { 57 | Layout.preferredWidth: 160 58 | text: model.localAddress 59 | } 60 | PlasmaComponents.Label { 61 | Layout.preferredWidth: 160 62 | text: model.foreignAddress 63 | } 64 | PlasmaComponents.Label { 65 | Layout.preferredWidth: 100 66 | text: model.status 67 | } 68 | // PlasmaComponents.Label { 69 | // Layout.preferredWidth: 40 70 | // text: model.pid 71 | // } 72 | PlasmaComponents.Label { 73 | Layout.preferredWidth: 120 74 | text: model.program 75 | } 76 | } 77 | 78 | PlasmaComponents.ToolButton { 79 | anchors.right: parent.right 80 | anchors.rightMargin: 24 81 | anchors.verticalCenter: parent.verticalCenter 82 | visible: itemRoot.containsMouse 83 | 84 | height: 48 85 | iconSource: "view-filter" 86 | onClicked: itemRoot.filterConnection(model.protocol, model.localAddress, 87 | model.foreignAddress, model.status) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /kcm/package/contents/ui/ConnectionsView.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Alexis Lopes Zubeta 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | import QtQuick 2.7 22 | import QtQuick.Layouts 1.3 23 | 24 | import org.kde.plasma.core 2.0 as PlasmaCore 25 | import org.kde.plasma.components 2.0 as PlasmaComponents 26 | import org.kde.plasma.extras 2.0 as PlasmaExtras 27 | 28 | Item { 29 | id: connectionsViewRoot 30 | 31 | 32 | PlasmaExtras.ScrollArea { 33 | anchors.fill: parent 34 | ListView { 35 | clip: true 36 | anchors.fill: parent 37 | model: netStatClient.connections() 38 | delegate: ConnectionItemDelegate { 39 | onFilterConnection: mainWindow.createRuleFromConnection(protocol, localAddress, foreignAddres, status) 40 | 41 | } 42 | 43 | headerPositioning: ListView.OverlayHeader 44 | header: PlasmaCore.FrameSvgItem { 45 | height: 40 46 | z: 100 47 | 48 | anchors.left: parent.left 49 | anchors.right: parent.right 50 | 51 | imagePath: "opaque/widgets/panel-background" 52 | enabledBorders: PlasmaCore.FrameSvgItem.NoBorder 53 | 54 | RowLayout { 55 | anchors.verticalCenter: parent.verticalCenter 56 | PlasmaComponents.Label { 57 | Layout.leftMargin: 12 58 | Layout.preferredWidth: 60 59 | text: i18n("Protocol") 60 | } 61 | PlasmaComponents.Label { 62 | Layout.preferredWidth: 160 63 | text: i18n("Local Address") 64 | } 65 | PlasmaComponents.Label { 66 | Layout.preferredWidth: 160 67 | text: i18n("Foreign Address") 68 | } 69 | PlasmaComponents.Label { 70 | Layout.preferredWidth: 100 71 | text: i18n("Status") 72 | } 73 | // PlasmaComponents.Label { 74 | // Layout.preferredWidth: 40 75 | // text: i18n("PID") 76 | // } 77 | PlasmaComponents.Label { 78 | Layout.preferredWidth: 120 79 | text: i18n("Program") 80 | } 81 | } 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /kcm/package/contents/ui/GlobalRules.qml: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2018 Alexis Lopes Zubeta 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License or (at your option) version 3 or any later version 9 | * accepted by the membership of KDE e.V. (or its successor approved 10 | * by the membership of KDE e.V.), which shall act as a proxy 11 | * defined in Section 14 of version 3 of the license. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | import QtQuick 2.7 23 | import QtQuick.Layouts 1.3 24 | 25 | 26 | import org.kde.plasma.components 2.0 as PlasmaComponents 27 | import org.kde.plasma.extras 2.0 as PlasmaExtras 28 | 29 | ColumnLayout { 30 | 31 | RowLayout { 32 | Rectangle { 33 | height: 28 34 | width: 28 35 | radius: 14 36 | color: ufwClient.enabled ? "lightgreen" : "lightgray" 37 | } 38 | 39 | PlasmaExtras.Heading { 40 | level: 3 41 | Layout.leftMargin: 12 42 | Layout.fillWidth: true 43 | Layout.alignment: Qt.AlignLeft 44 | text: ufwClient.enabled ? i18n("Firewall enabled") : i18n( 45 | "Firewall disabled") 46 | } 47 | 48 | PlasmaComponents.Button { 49 | text: ufwClient.enabled ? i18n("Disable") : i18n("Enable") 50 | onClicked: ufwClient.enabled = !ufwClient.enabled 51 | } 52 | } 53 | 54 | RowLayout { 55 | Layout.topMargin: 12 56 | PlasmaExtras.Heading { 57 | level: 4 58 | text: i18n("Default Incoming Policy:") 59 | } 60 | 61 | PlasmaComponents.ButtonRow { 62 | Layout.leftMargin: 24 63 | PlasmaComponents.Button { 64 | text: i18n("Allow") 65 | checked: ufwClient.defaultIncomingPolicy === "allow" 66 | onClicked: ufwClient.defaultIncomingPolicy = "allow" 67 | } 68 | PlasmaComponents.Button { 69 | text: i18n("Deny") 70 | checked: ufwClient.defaultIncomingPolicy === "deny" 71 | onClicked: ufwClient.defaultIncomingPolicy = "deny" 72 | } 73 | PlasmaComponents.Button { 74 | text: i18n("Reject") 75 | checked: ufwClient.defaultIncomingPolicy === "reject" 76 | onClicked: ufwClient.defaultIncomingPolicy = "reject" 77 | } 78 | } 79 | } 80 | 81 | RowLayout { 82 | PlasmaExtras.Heading { 83 | level: 4 84 | text: i18n("Default Outgoing Policy:") 85 | } 86 | 87 | PlasmaComponents.ButtonRow { 88 | Layout.leftMargin: 24 89 | PlasmaComponents.Button { 90 | text: i18n("Allow") 91 | checked: ufwClient.defaultOutgoingPolicy === "allow" 92 | onClicked: ufwClient.defaultOutgoingPolicy = "allow" 93 | } 94 | PlasmaComponents.Button { 95 | text: i18n("Deny") 96 | checked: ufwClient.defaultOutgoingPolicy === "deny" 97 | onClicked: ufwClient.defaultOutgoingPolicy = "deny" 98 | } 99 | PlasmaComponents.Button { 100 | text: i18n("Reject") 101 | checked: ufwClient.defaultOutgoingPolicy === "reject" 102 | onClicked: ufwClient.defaultOutgoingPolicy = "reject" 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /kcm/package/contents/ui/LogItemDelegate.qml: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2018 Alexis Lopes Zubeta 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License or (at your option) version 3 or any later version 9 | * accepted by the membership of KDE e.V. (or its successor approved 10 | * by the membership of KDE e.V.), which shall act as a proxy 11 | * defined in Section 14 of version 3 of the license. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | import QtQuick 2.0 23 | import QtQuick.Layouts 1.3 24 | 25 | import org.kde.plasma.core 2.0 as PlasmaCore 26 | import org.kde.plasma.components 2.0 as PlasmaComponents 27 | import org.kde.plasma.extras 2.0 as PlasmaExtras 28 | 29 | PlasmaComponents.ListItem { 30 | id: itemRoot 31 | height: 42 32 | 33 | MouseArea { 34 | anchors.fill: parent 35 | onEntered: filterButton.visible = true 36 | onExited: filterButton.visible = false 37 | hoverEnabled: true 38 | } 39 | RowLayout { 40 | id: itemLayout 41 | spacing: 0 42 | anchors.fill: parent 43 | 44 | PlasmaComponents.Label { 45 | Layout.leftMargin: 14 46 | text: "" + model.time + "" 47 | } 48 | 49 | PlasmaComponents.Label { 50 | Layout.leftMargin: 12 51 | text: i18n("from") + " %1".arg(sourceAddress) 52 | 53 | MouseArea { 54 | anchors.fill: parent 55 | onClicked: Qt.openUrlExternally( 56 | "https://www.geoiptool.com/?ip=%1".arg( 57 | sourceAddress)) 58 | cursorShape: Qt.PointingHandCursor 59 | } 60 | } 61 | PlasmaComponents.Label { 62 | Layout.leftMargin: 0 63 | text: ":" + sourcePort 64 | visible: sourcePort 65 | } 66 | 67 | PlasmaComponents.Label { 68 | Layout.leftMargin: 6 69 | text: i18n("to ") + destinationAddress + "" 70 | 71 | MouseArea { 72 | anchors.fill: parent 73 | onClicked: Qt.openUrlExternally( 74 | "https://www.geoiptool.com/?ip=%1".arg( 75 | destinationAddress)) 76 | cursorShape: Qt.PointingHandCursor 77 | } 78 | } 79 | PlasmaComponents.Label { 80 | Layout.leftMargin: 0 81 | text: ":" + destinationPort 82 | visible: destinationPort 83 | } 84 | PlasmaComponents.Label { 85 | visible: false 86 | Layout.leftMargin: 4 87 | text: i18n(" at %1", model.interface) 88 | } 89 | PlasmaComponents.Label { 90 | Layout.fillWidth: true 91 | } 92 | 93 | // PlasmaCore.IconItem { 94 | // source: action == "UFW BLOCK" ? "tab-close" : "" 95 | // } 96 | PlasmaComponents.Label { 97 | text: model.action 98 | } 99 | 100 | Text { 101 | Layout.preferredWidth: 40 102 | Layout.leftMargin: 6 103 | horizontalAlignment: Text.AlignHCenter 104 | text: protocol.toLowerCase() 105 | color: { 106 | if (protocol.startsWith("UDP")) 107 | return "brown" 108 | if (protocol.startsWith("TCP")) 109 | return "#006501" 110 | return "gray" 111 | } 112 | } 113 | 114 | Item { 115 | height: 32 116 | width: 32 117 | PlasmaComponents.ToolButton { 118 | id: filterButton 119 | anchors.fill: parent 120 | visible: false 121 | onHoveredChanged: visible = hovered 122 | 123 | iconSource: "view-filter" 124 | onClicked: mainWindow.createRuleFromLog(model.protocol, 125 | model.sourceAddress, 126 | model.sourcePort, 127 | model.destinationAddress, 128 | model.destinationPort, 129 | model.interface) 130 | } 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /kcm/package/contents/ui/LogsView.qml: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2018 Alexis Lopes Zubeta 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License or (at your option) version 3 or any later version 9 | * accepted by the membership of KDE e.V. (or its successor approved 10 | * by the membership of KDE e.V.), which shall act as a proxy 11 | * defined in Section 14 of version 3 of the license. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | import QtQuick 2.0 23 | import QtQuick.Layouts 1.3 24 | 25 | import org.kde.plasma.core 2.0 as PlasmaCore 26 | import org.kde.plasma.components 2.0 as PlasmaComponents 27 | import org.kde.plasma.extras 2.0 as PlasmaExtras 28 | 29 | Item { 30 | id: root 31 | Component { 32 | id: sectionHeading 33 | PlasmaComponents.ListItem { 34 | sectionDelegate: true 35 | Item { 36 | height: 40 37 | width: 200 38 | PlasmaExtras.Heading { 39 | anchors.fill: parent 40 | anchors.leftMargin: 12 41 | // horizontalAlignment: Text.AlignHCenter 42 | text: section 43 | } 44 | } 45 | } 46 | } 47 | 48 | PlasmaExtras.ScrollArea { 49 | anchors.fill: parent 50 | ListView { 51 | model: ufwClient.logs() 52 | delegate: LogItemDelegate { 53 | id: itemRoot 54 | width: root.width - 10 55 | } 56 | 57 | section.property: "date" 58 | section.criteria: ViewSection.FullString 59 | section.delegate: sectionHeading 60 | 61 | add: Transition { 62 | NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 400 } 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /kcm/package/contents/ui/RuleEdit.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | import QtQuick.Layouts 1.1 4 | 5 | import org.kde.plasma.core 2.0 as PlasmaCore 6 | import org.kde.plasma.components 2.0 as PlasmaComponents 7 | import org.kde.plasma.extras 2.0 as PlasmaExtras 8 | 9 | import org.nomad.ufw 1.0 as UFW 10 | 11 | Popup { 12 | focus: true 13 | closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent 14 | 15 | signal accept(var rule) 16 | property var rule: UFW.Rule { 17 | policy: "deny" 18 | incoming: true 19 | logging: "none" 20 | } 21 | property bool newRule: false 22 | 23 | background: PlasmaCore.FrameSvgItem { 24 | anchors.fill: parent 25 | imagePath: "opaque/dialogs/background" 26 | } 27 | 28 | onAccept: { 29 | if (newRule) 30 | ufwClient.addRule(rule) 31 | else 32 | ufwClient.updateRule(rule) 33 | 34 | close() 35 | } 36 | Component.onCompleted: open() 37 | 38 | GridLayout { 39 | anchors.fill: parent 40 | 41 | columns: 6 42 | // rowSpacing: 24 43 | 44 | PlasmaExtras.Heading { 45 | level: 4 46 | text: i18n("Policy:") 47 | } 48 | 49 | PlasmaComponents.ButtonRow { 50 | Layout.columnSpan: 5 51 | PlasmaComponents.Button { 52 | text: i18n("Allow") 53 | checked: rule.policy === "allow" 54 | onClicked: rule.policy = "allow" 55 | } 56 | PlasmaComponents.Button { 57 | text: i18n("Deny") 58 | checked: rule.policy === "deny" 59 | onClicked: rule.policy = "deny" 60 | } 61 | PlasmaComponents.Button { 62 | text: i18n("Reject") 63 | checked: rule.policy === "reject" 64 | onClicked: rule.policy = "reject" 65 | } 66 | PlasmaComponents.Button { 67 | text: i18n("Limit") 68 | checked: rule.policy === "limit" 69 | onClicked: rule.policy = "limit" 70 | } 71 | } 72 | 73 | PlasmaExtras.Heading { 74 | level: 4 75 | text: i18n("Direction:") 76 | } 77 | 78 | PlasmaComponents.ButtonRow { 79 | Layout.columnSpan: 5 80 | PlasmaComponents.Button { 81 | text: i18n("Incoming") 82 | iconName: "arrow-down" 83 | checked: rule.incoming 84 | onClicked: rule.incoming = true 85 | } 86 | PlasmaComponents.Button { 87 | text: i18n("Outgoing") 88 | iconName: "arrow-up" 89 | checked: !rule.incoming 90 | onClicked: rule.incoming = false 91 | } 92 | } 93 | 94 | GroupBox { 95 | title: i18n("Source") 96 | 97 | Layout.fillWidth: true 98 | Layout.columnSpan: 3 99 | 100 | GridLayout { 101 | columns: 3 102 | anchors.fill: parent 103 | PlasmaComponents.Label { 104 | text: i18n("Address:") 105 | } 106 | PlasmaComponents.TextField { 107 | id: sourceAddress 108 | Layout.fillWidth: true 109 | 110 | placeholderText: "0.0.0.0/0" 111 | text: rule.sourceAddress 112 | onTextChanged: rule.sourceAddress = text 113 | property var originalValue 114 | 115 | Component.onCompleted: originalValue = rule.sourceAddress 116 | } 117 | PlasmaComponents.CheckBox { 118 | text: i18n("Any") 119 | checked: sourceAddress.text == "" 120 | || sourceAddress.text == "0.0.0.0/0" 121 | onClicked: sourceAddress.text = checked ? "" : sourceAddress.originalValue 122 | } 123 | PlasmaComponents.Label { 124 | text: i18n("Port:") 125 | } 126 | PlasmaComponents.TextField { 127 | id: sourcePort 128 | text: rule.sourcePort 129 | onTextChanged: rule.sourcePort = text 130 | placeholderText: "0/0" 131 | property var originalValue 132 | 133 | Component.onCompleted: originalValue = rule.sourcePort 134 | } 135 | PlasmaComponents.CheckBox { 136 | text: i18n("Any") 137 | Layout.fillWidth: true 138 | 139 | checked: sourcePort.text == "" || sourcePort.text == "0/0" 140 | onClicked: sourcePort.text = checked ? "" : sourcePort.originalValue 141 | } 142 | } 143 | } 144 | 145 | GroupBox { 146 | title: i18n("Destination") 147 | 148 | Layout.fillWidth: true 149 | Layout.columnSpan: 3 150 | 151 | GridLayout { 152 | anchors.fill: parent 153 | columns: 3 154 | PlasmaComponents.Label { 155 | text: i18n("Address:") 156 | } 157 | PlasmaComponents.TextField { 158 | id: destinationAddress 159 | Layout.fillWidth: true 160 | 161 | placeholderText: "0.0.0.0/0" 162 | text: rule.destinationAddress 163 | onTextChanged: rule.destinationAddress = text 164 | } 165 | PlasmaComponents.CheckBox { 166 | text: i18n("Any") 167 | checked: destinationAddress.text == "" 168 | || destinationAddress.text == "0.0.0.0/0" 169 | } 170 | PlasmaComponents.Label { 171 | text: i18n("Port:") 172 | } 173 | PlasmaComponents.TextField { 174 | id: destinationPort 175 | 176 | placeholderText: "0/0" 177 | text: rule.destinationPort 178 | onTextChanged: rule.destinationPort = text 179 | } 180 | PlasmaComponents.CheckBox { 181 | text: i18n("Any") 182 | checked: destinationPort.text == "" 183 | || destinationPort.text == "0/0" 184 | 185 | Layout.fillWidth: true 186 | } 187 | } 188 | } 189 | PlasmaExtras.Heading { 190 | level: 4 191 | text: i18n("Protocol:") 192 | } 193 | PlasmaComponents.ComboBox { 194 | id: protocolCb 195 | 196 | model: ufwClient.getKnownProtocols() 197 | 198 | currentIndex: rule.protocol 199 | onCurrentIndexChanged: rule.protocol = currentIndex 200 | 201 | Layout.columnSpan: 2 202 | } 203 | PlasmaExtras.Heading { 204 | level: 4 205 | text: i18n("Interface:") 206 | } 207 | PlasmaComponents.ComboBox { 208 | id: interfaceCb 209 | 210 | model: ufwClient.getKnownInterfaces() 211 | 212 | currentIndex: rule.interface 213 | onCurrentIndexChanged: rule.interface = currentIndex 214 | 215 | Layout.columnSpan: 2 216 | } 217 | PlasmaExtras.Heading { 218 | level: 4 219 | text: i18n("Logging:") 220 | } 221 | 222 | PlasmaComponents.ButtonRow { 223 | Layout.columnSpan: 5 224 | PlasmaComponents.Button { 225 | text: i18n("None") 226 | checked: rule.logging === "none" 227 | onClicked: rule.logging = "none" 228 | } 229 | PlasmaComponents.Button { 230 | text: i18n("New connections") 231 | checked: rule.logging === "log" 232 | onClicked: rule.logging = "log" 233 | } 234 | PlasmaComponents.Button { 235 | text: i18n("All Packets") 236 | checked: rule.logging === "log-all" 237 | onClicked: rule.logging = "log-all" 238 | } 239 | } 240 | 241 | 242 | PlasmaComponents.Button { 243 | text: i18n("Cancel") 244 | iconName: "dialog-cancel" 245 | 246 | onClicked: close() 247 | } 248 | 249 | PlasmaComponents.Button { 250 | text: i18n("Accept") 251 | iconName: "dialog-ok" 252 | Layout.columnSpan: 5 253 | Layout.alignment: Qt.AlignRight 254 | 255 | onClicked: accept(rule) 256 | } 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /kcm/package/contents/ui/RuleListItem.qml: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2018 Alexis Lopes Zubeta 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License or (at your option) version 3 or any later version 9 | * accepted by the membership of KDE e.V. (or its successor approved 10 | * by the membership of KDE e.V.), which shall act as a proxy 11 | * defined in Section 14 of version 3 of the license. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | import QtQuick 2.0 23 | import QtQuick.Layouts 1.3 24 | import QtQuick.Controls 1.4 25 | 26 | import org.kde.plasma.core 2.0 as PlasmaCore 27 | import org.kde.plasma.components 2.0 as PlasmaComponents 28 | 29 | Item { 30 | id: itemRoot 31 | 32 | property bool dropAreasVisible: false 33 | 34 | signal move(int from, int to) 35 | signal edit(int index) 36 | signal remove(int index) 37 | 38 | height: upperSpacer.height + dragableItem.height + lowerSpacer.height 39 | 40 | DropArea { 41 | id: upperDropArea 42 | anchors { 43 | top: parent.top 44 | bottom: dragableItem.verticalCenter 45 | left: parent.left 46 | right: parent.right 47 | } 48 | 49 | visible: dropAreasVisible && !dragArea.drag.active 50 | enabled: !dragArea.drag.active && index == 0 51 | 52 | onEntered: drag.source.dropIndex = index 53 | onExited: drag.source.dropIndex = 0 54 | } 55 | 56 | PlasmaCore.FrameSvgItem { 57 | id: upperSpacer 58 | anchors.left: parent.left 59 | anchors.right: parent.right 60 | imagePath: "translucent/widgets/panel-background" 61 | 62 | height: 0 63 | visible: false 64 | 65 | PlasmaComponents.Label { 66 | text: i18n("Drop rule") 67 | anchors.centerIn: parent 68 | } 69 | 70 | states: [ 71 | State { 72 | name: "expanded" 73 | when: upperDropArea.containsDrag 74 | PropertyChanges { 75 | target: upperSpacer 76 | height: dragableItem.height 77 | visible: true 78 | } 79 | } 80 | ] 81 | 82 | transitions: Transition { 83 | NumberAnimation { 84 | properties: "height" 85 | easing.type: Easing.InOutQuad 86 | duration: 200 87 | } 88 | } 89 | } 90 | 91 | PlasmaComponents.ListItem { 92 | id: dragableItem 93 | y: upperSpacer.height 94 | 95 | anchors.left: parent.left 96 | anchors.right: parent.right 97 | height: 42 98 | 99 | property int dropIndex: -1 100 | property int base_x: 0 101 | property int base_y: 0 102 | 103 | Component.onCompleted: { 104 | dragableItem.base_x = dragableItem.x 105 | dragableItem.base_y = dragableItem.y 106 | } 107 | 108 | MouseArea { 109 | id: itemRootMouseArea 110 | anchors.fill: parent 111 | hoverEnabled: true 112 | 113 | acceptedButtons: Qt.LeftButton 114 | onClicked: edit(index) 115 | 116 | onEntered: eraseButton.visible = true 117 | onExited: eraseButton.visible = false 118 | propagateComposedEvents: true 119 | } 120 | 121 | checked: dragArea.drag.active 122 | 123 | Drag.active: dragArea.drag.active 124 | Drag.hotSpot.x: dragArea.width / 2 125 | Drag.hotSpot.y: dragArea.height / 2 126 | 127 | z: Drag.active ? 100 : 0 128 | 129 | RowLayout { 130 | anchors.fill: parent 131 | 132 | Item { 133 | Layout.leftMargin: 4 134 | height: 32 135 | width: 32 136 | 137 | PlasmaCore.IconItem { 138 | anchors.centerIn: parent 139 | height: 18 140 | width: height 141 | source: "application-menu" 142 | visible: itemRootMouseArea.containsMouse 143 | } 144 | 145 | MouseArea { 146 | id: dragArea 147 | anchors.fill: parent 148 | drag.target: dragableItem 149 | cursorShape: dragArea.pressed ? Qt.DragMoveCursor : Qt.OpenHandCursor 150 | onReleased: { 151 | // allways return the item to it's original position 152 | dragableItem.x = dragableItem.base_x 153 | dragableItem.y = Qt.binding(function () {return upperSpacer.height}) 154 | 155 | // if (dragableItem.dropIndex != index 156 | // && dragableItem.dropIndex - 1 != index) 157 | move(index, dragableItem.dropIndex) 158 | } 159 | } 160 | } 161 | 162 | PlasmaComponents.Label { 163 | Layout.minimumWidth: 120 164 | Layout.fillHeight: true 165 | Layout.leftMargin: 4 166 | text: model.action 167 | } 168 | PlasmaComponents.Label { 169 | Layout.minimumWidth: 160 170 | text: model.from 171 | } 172 | PlasmaComponents.Label { 173 | Layout.minimumWidth: 160 174 | text: model.to 175 | } 176 | // PlasmaComponents.Label { 177 | // Layout.minimumWidth: 60 178 | // text: model.ipv6 ? "IPv6" : "" 179 | // } 180 | PlasmaComponents.Label { 181 | Layout.leftMargin: 12 182 | text: model.logging 183 | } 184 | 185 | Item { 186 | // Layout.fillWidth: true 187 | height: 32 188 | width: 32 189 | 190 | PlasmaComponents.ToolButton { 191 | id: eraseButton 192 | minimumHeight: 32 193 | minimumWidth: 32 194 | 195 | visible: false 196 | onHoveredChanged: visible = hovered 197 | 198 | iconSource: "user-trash" 199 | onClicked: itemRoot.remove(index) 200 | } 201 | } 202 | } 203 | } 204 | 205 | 206 | 207 | DropArea { 208 | id: lowerDropArea 209 | anchors { 210 | top: dragableItem.verticalCenter 211 | bottom: parent.bottom 212 | left: parent.left 213 | right: parent.right 214 | } 215 | 216 | visible: dropAreasVisible && !dragArea.drag.active 217 | enabled: !dragArea.drag.active 218 | 219 | onEntered: drag.source.dropIndex = index + 1 220 | onExited: drag.source.dropIndex = -1 221 | } 222 | 223 | PlasmaCore.FrameSvgItem { 224 | id: lowerSpacer 225 | anchors.left: parent.left 226 | anchors.right: parent.right 227 | imagePath: "translucent/widgets/panel-background" 228 | 229 | y: dragableItem.height 230 | height: 0 231 | visible: false 232 | 233 | PlasmaComponents.Label { 234 | text: i18n("Drop rule ") 235 | anchors.centerIn: parent 236 | } 237 | 238 | states: [ 239 | State { 240 | name: "expanded" 241 | when: lowerDropArea.containsDrag 242 | PropertyChanges { 243 | target: lowerSpacer 244 | height: dragableItem.height 245 | visible: true 246 | } 247 | } 248 | ] 249 | 250 | transitions: Transition { 251 | NumberAnimation { 252 | properties: "height" 253 | easing.type: Easing.InOutQuad 254 | duration: 200 255 | } 256 | } 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /kcm/package/contents/ui/RulesView.qml: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2018 Alexis Lopes Zubeta 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License or (at your option) version 3 or any later version 9 | * accepted by the membership of KDE e.V. (or its successor approved 10 | * by the membership of KDE e.V.), which shall act as a proxy 11 | * defined in Section 14 of version 3 of the license. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | import QtQuick 2.0 23 | import QtQuick.Layouts 1.3 24 | import QtQuick.Controls 1.4 25 | 26 | import org.kde.plasma.core 2.0 as PlasmaCore 27 | import org.kde.plasma.components 2.0 as PlasmaComponents 28 | import org.kde.plasma.extras 2.0 as PlasmaExtras 29 | 30 | import org.nomad.ufw 1.0 as UFW 31 | 32 | ColumnLayout { 33 | spacing: 12 34 | GlobalRules { 35 | } 36 | 37 | FocusScope { 38 | id: rulesViewRoot 39 | 40 | Layout.topMargin: 6 41 | Layout.fillWidth: true 42 | Layout.fillHeight: true 43 | 44 | clip: true 45 | 46 | Component { 47 | id: sectionHeading 48 | PlasmaComponents.ListItem { 49 | sectionDelegate: true 50 | Item { 51 | height: 32 52 | width: 200 53 | PlasmaExtras.Heading { 54 | anchors.fill: parent 55 | anchors.leftMargin: 12 56 | level: 4 57 | text: section == "true" ? "IPv6" : "IPv4" 58 | } 59 | } 60 | } 61 | } 62 | 63 | PlasmaExtras.ScrollArea { 64 | id: listScrollArea 65 | anchors.fill: parent 66 | 67 | ListView { 68 | id: listView 69 | model: ufwClient.rules() 70 | bottomMargin: 48 * 2 71 | delegate: RuleListItem { 72 | dropAreasVisible: true 73 | width: listView.width 74 | onMove: function (from, to) { 75 | // print("moving ", from, " to ", to) 76 | if (from < to) 77 | to = to - 1 78 | 79 | // Force valid positions 80 | to = Math.max(0, to) 81 | to = Math.min(listView.model.rowCount(), to) 82 | 83 | if (from !== to) { 84 | // listView.model.move(from, to) 85 | ufwClient.moveRule(from, to) 86 | } 87 | } 88 | 89 | onEdit: function (index) { 90 | var rule = ufwClient.getRule(index) 91 | ruleDetailsLoader.setSource("RuleEdit.qml", { 92 | rule: rule, 93 | newRule: false, 94 | x: 0, 95 | y: 0, 96 | height: mainWindow.height, 97 | width: mainWindow.width 98 | }) 99 | } 100 | 101 | onRemove: function (index) { 102 | ufwClient.removeRule(index) 103 | } 104 | } 105 | 106 | section.property: "ipv6" 107 | section.criteria: ViewSection.FullString 108 | section.delegate: sectionHeading 109 | } 110 | } 111 | 112 | PlasmaComponents.ToolButton { 113 | height: 48 114 | iconSource: "list-add" 115 | text: i18n("New Rule") 116 | 117 | onClicked: { 118 | ruleDetailsLoader.setSource("RuleEdit.qml", { 119 | newRule: true, 120 | x: 0, 121 | y: 0, 122 | height: mainWindow.height, 123 | width: mainWindow.width 124 | }) 125 | } 126 | 127 | anchors.bottom: parent.bottom 128 | anchors.bottomMargin: 12 129 | anchors.right: parent.right 130 | // anchors.rightMargin: 12 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /kcm/package/contents/ui/main.qml: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2018 Alexis Lopes Zubeta 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License or (at your option) version 3 or any later version 9 | * accepted by the membership of KDE e.V. (or its successor approved 10 | * by the membership of KDE e.V.), which shall act as a proxy 11 | * defined in Section 14 of version 3 of the license. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | import QtQuick 2.6 23 | import QtQuick.Layouts 1.3 24 | import QtQuick.Controls 2.12 as QQC2 25 | 26 | import org.kde.kcm 1.0 27 | import org.nomad.ufw 1.0 28 | import org.nomad.netstat 1.0 29 | 30 | import org.kde.kirigami 2.4 as Kirigami 31 | import org.kde.kcm 1.1 as KCM 32 | 33 | KCM.SimpleKCM { 34 | id: root 35 | 36 | implicitHeight: Kirigami.Units.gridUnit * 22 37 | 38 | KCM.ConfigModule.quickHelp: i18n("This module lets you configure firewall.") 39 | 40 | UfwClient { 41 | id: ufwClient 42 | logsAutoRefresh: tabButtons.currentTab == logsTabButton 43 | } 44 | 45 | NetstatClient { 46 | id: netStatClient 47 | } 48 | 49 | Loader { 50 | id: ruleDetailsLoader 51 | anchors.fill: parent 52 | } 53 | 54 | ColumnLayout { 55 | QQC2.TabBar { 56 | id: tabButtons 57 | 58 | QQC2.TabButton { 59 | text: i18n("Rules") 60 | } 61 | QQC2.TabButton { 62 | text: i18n("Connections") 63 | } 64 | QQC2.TabButton { 65 | text: i18n("Logs") 66 | } 67 | } 68 | 69 | StackLayout { 70 | id: tabGroup 71 | currentIndex: tabButtons.currentIndex 72 | 73 | Layout.fillWidth: true 74 | Layout.fillHeight: true 75 | 76 | RulesView { 77 | Layout.fillWidth: true 78 | Layout.fillHeight: true 79 | } 80 | 81 | ConnectionsView { 82 | Layout.fillWidth: true 83 | Layout.fillHeight: true 84 | } 85 | 86 | LogsView { 87 | Layout.fillWidth: true 88 | Layout.fillHeight: true 89 | } 90 | } 91 | 92 | QQC2.Label { 93 | text: ufwClient.status 94 | } 95 | } 96 | 97 | function createRuleFromConnection(protocol, localAddress, foreignAddres, status) { 98 | // Transform to the ufw notation 99 | localAddress = localAddress.replace("*", "") 100 | foreignAddres = foreignAddres.replace("*", "") 101 | 102 | localAddress = localAddress.replace("0.0.0.0", "") 103 | foreignAddres = foreignAddres.replace("0.0.0.0", "") 104 | 105 | var localAddressData = localAddress.split(":") 106 | var foreignAddresData = foreignAddres.split(":") 107 | 108 | var rule = Qt.createQmlObject("import org.nomad.ufw 1.0; Rule {}", 109 | mainWindow) 110 | 111 | // Prepare rule draft 112 | if (status === "LISTEN") { 113 | // Create deny incoming rule 114 | rule.incoming = true 115 | rule.policy = "deny" 116 | 117 | rule.sourceAddress = foreignAddresData[0] 118 | rule.sourcePort = foreignAddresData[1] 119 | 120 | rule.destinationAddress = localAddressData[0] 121 | rule.destinationPort = localAddressData[1] 122 | } else { 123 | // Create deny outgoing rule 124 | rule.incoming = false 125 | rule.policy = "deny" 126 | 127 | rule.sourceAddress = localAddressData[0] 128 | rule.sourcePort = localAddressData[1] 129 | 130 | rule.destinationAddress = foreignAddresData[0] 131 | rule.destinationPort = foreignAddresData[1] 132 | } 133 | 134 | var protocols = ufwClient.getKnownProtocols() 135 | rule.protocol = protocols.indexOf(protocol.toUpperCase()) 136 | 137 | ruleDetailsLoader.setSource("RuleEdit.qml", { 138 | rule: rule, 139 | newRule: true, 140 | x: 0, 141 | y: 0, 142 | height: mainWindow.height, 143 | width: mainWindow.width 144 | }) 145 | } 146 | 147 | function createRuleFromLog(protocol, sourceAddress, sourcePort, destinationAddress, destinationPort, inn, out) { 148 | // Transform to the ufw notation 149 | sourceAddress = sourceAddress.replace("*", "") 150 | destinationAddress = destinationAddress.replace("*", "") 151 | 152 | sourceAddress = sourceAddress.replace("0.0.0.0", "") 153 | destinationAddress = destinationAddress.replace("0.0.0.0", "") 154 | 155 | var rule = Qt.createQmlObject("import org.nomad.ufw 1.0; Rule {}", 156 | mainWindow) 157 | 158 | // Prepare rule draft 159 | rule.incoming = (inn !== "") 160 | rule.policy = "allow" 161 | rule.sourceAddress = sourceAddress 162 | rule.sourcePort = sourcePort 163 | 164 | rule.destinationAddress = destinationAddress 165 | rule.destinationPort = destinationPort 166 | 167 | var protocols = ufwClient.getKnownProtocols() 168 | rule.protocol = protocols.indexOf(protocol.toUpperCase()) 169 | 170 | ruleDetailsLoader.setSource("RuleEdit.qml", { 171 | rule: rule, 172 | newRule: true, 173 | x: 0, 174 | y: 0, 175 | height: mainWindow.height, 176 | width: mainWindow.width 177 | }) 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /kcm/package/metadata.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=NX Firewall 3 | Comment=Adjust your firewall settings 4 | Encoding=UTF-8 5 | 6 | Icon=security-high 7 | Type=Service 8 | X-KDE-ServiceTypes=KCModule 9 | X-KDE-ServiceTypes=Plasma/Generic 10 | 11 | X-Plasma-API=declarativeappletscript 12 | X-Plasma-MainScript=ui/main.qml 13 | 14 | X-KDE-PluginInfo-Name=org.nxos.firewall 15 | X-KDE-PluginInfo-Category=network 16 | X-KDE-PluginInfo-Author=Alexis López Zubieta 17 | X-KDE-PluginInfo-Email=azubieta90gmail.com 18 | X-KDE-PluginInfo-Version=1.0.0 19 | X-KDE-PluginInfo-Website= 20 | X-KDE-PluginInfo-License=GPL 21 | -------------------------------------------------------------------------------- /kcm/version.h.cmake: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2017 Alexis López Zubieta 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License as 6 | published by the Free Software Foundation; either version 2 of 7 | the License or (at your option) version 3 or any later version 8 | accepted by the membership of KDE e.V. (or its successor approved 9 | by the membership of KDE e.V.), which shall act as a proxy 10 | defined in Section 14 of version 3 of the license. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | #ifndef VERSION_H 22 | #define VERSION_H 23 | 24 | static const char global_s_versionString[] = "${VERSION_STRING}"; 25 | static const char global_s_versionStringFull[] = "${VERSION_STRING_FULL}"; 26 | 27 | #endif // VERSION_H 28 | -------------------------------------------------------------------------------- /plugins/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(ufw) 2 | add_subdirectory(netstat) 3 | -------------------------------------------------------------------------------- /plugins/netstat/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(helper) 2 | 3 | find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS 4 | Quick 5 | Xml 6 | X11Extras 7 | ) 8 | 9 | find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS 10 | Plasma 11 | PlasmaQuick 12 | I18n 13 | Declarative 14 | Auth 15 | Config 16 | ) 17 | 18 | 19 | set(nomad_netstat_plugin_SRCS 20 | netstatplugin.cpp 21 | conectionsmodel.cpp 22 | netstatclient.cpp 23 | qmldir 24 | ) 25 | 26 | add_library(nomad_netstat_plugin SHARED ${nomad_netstat_plugin_SRCS}) 27 | target_link_libraries(nomad_netstat_plugin 28 | Qt5::Core 29 | Qt5::Quick 30 | Qt5::Xml 31 | Qt5::X11Extras 32 | KF5::CoreAddons 33 | KF5::ConfigCore 34 | KF5::Auth 35 | KF5::I18n) 36 | 37 | set(INSTALL_PATH ${QML_INSTALL_DIR}/org/nomad/netstat) 38 | 39 | install(TARGETS nomad_netstat_plugin DESTINATION ${INSTALL_PATH}) 40 | install(FILES qmldir DESTINATION ${INSTALL_PATH}) 41 | -------------------------------------------------------------------------------- /plugins/netstat/conectionsmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "conectionsmodel.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | ConnectionsModel::ConnectionsModel(QObject *parent) 8 | : QAbstractListModel(parent), m_queryRunning(false) 9 | { 10 | connect(&timer, &QTimer::timeout, this, &ConnectionsModel::refreshConnections); 11 | timer.setInterval(30000); 12 | timer.start(); 13 | 14 | QTimer::singleShot(200, this, &ConnectionsModel::refreshConnections); 15 | } 16 | 17 | int ConnectionsModel::rowCount(const QModelIndex &parent) const 18 | { 19 | // For list models only the root node (an invalid parent) should return the list's size. For all 20 | // other (valid) parents, rowCount() should return 0 so that it does not become a tree model. 21 | if (parent.isValid()) 22 | return 0; 23 | 24 | return m_connectionsData.size(); 25 | } 26 | 27 | QVariant ConnectionsModel::data(const QModelIndex &index, int role) const 28 | { 29 | if (!index.isValid()) 30 | return {}; 31 | 32 | if (index.row() < 0 || index.row() >= m_connectionsData.size()) 33 | return {}; 34 | 35 | QVariantList connection = m_connectionsData.at(index.row()).toList(); 36 | 37 | int value_index = role - ProtocolRole; 38 | if (value_index < 0 || value_index >= connection.size()) 39 | return {}; 40 | 41 | return connection.at(value_index); 42 | } 43 | 44 | QHash ConnectionsModel::roleNames() const 45 | { 46 | return { 47 | {ProtocolRole, "protocol"}, 48 | {LocalAddressRole, "localAddress"}, 49 | {ForeignAddressRole, "foreignAddress"}, 50 | {StatusRole, "status"}, 51 | {PidRole, "pid"}, 52 | {ProgramRole, "program"}, 53 | }; 54 | } 55 | 56 | void ConnectionsModel::refreshConnections() 57 | { 58 | if (m_queryRunning) 59 | { 60 | qWarning() << "Netstat client is bussy"; 61 | return; 62 | } 63 | 64 | m_queryRunning = true; 65 | 66 | KAuth::Action queryAction(QLatin1String("org.nxos.netstat.query")); 67 | queryAction.setHelperId("org.nxos.netstat"); 68 | 69 | KAuth::ExecuteJob *job = queryAction.execute(); 70 | connect(job, &KAuth::ExecuteJob::finished, [this] (KJob *kjob) 71 | { 72 | auto job = qobject_cast(kjob); 73 | if (!job->error()) 74 | { 75 | beginResetModel(); 76 | m_connectionsData = job->data().value("connections", QVariantList()).toList(); 77 | endResetModel(); 78 | } else 79 | qWarning() << "BACKEND ERROR: " << job->error() << job->errorText(); 80 | 81 | m_queryRunning = false; 82 | }); 83 | 84 | job->start(); 85 | } 86 | 87 | -------------------------------------------------------------------------------- /plugins/netstat/conectionsmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef CONECTIONSMODEL_H 2 | #define CONECTIONSMODEL_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | class ConnectionsModel : public QAbstractListModel 10 | { 11 | Q_OBJECT 12 | public: 13 | enum ConnectionsModelRoles 14 | { 15 | ProtocolRole = Qt::UserRole + 1, 16 | LocalAddressRole, 17 | ForeignAddressRole, 18 | StatusRole, 19 | PidRole, 20 | ProgramRole 21 | }; 22 | 23 | explicit ConnectionsModel(QObject *parent = nullptr); 24 | 25 | // Basic functionality: 26 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; 27 | 28 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 29 | QHash roleNames() const override; 30 | 31 | protected slots: 32 | void refreshConnections(); 33 | 34 | private: 35 | bool m_queryRunning; 36 | QVariantList m_connectionsData; 37 | QTimer timer; 38 | }; 39 | 40 | #endif // CONECTIONSMODEL_H 41 | -------------------------------------------------------------------------------- /plugins/netstat/helper/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Find includes in corresponding build directories 2 | include_directories(${CMAKE_BINARY_DIR}) 3 | 4 | # Instruct CMake to run moc automatically when needed. 5 | set(CMAKE_AUTOMOC ON) 6 | 7 | find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS 8 | Core 9 | ) 10 | 11 | 12 | find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS 13 | I18n 14 | Auth 15 | ) 16 | 17 | add_executable(nxos_netstat_helper netstathelper.cpp) 18 | target_link_libraries(nxos_netstat_helper Qt5::Core KF5::I18n KF5::Auth) 19 | 20 | install(TARGETS nxos_netstat_helper DESTINATION ${KAUTH_HELPER_INSTALL_DIR}) 21 | kauth_install_helper_files(nxos_netstat_helper org.nxos.netstat root) 22 | 23 | kauth_install_actions(org.nxos.netstat org.nxos.netstat.actions) 24 | -------------------------------------------------------------------------------- /plugins/netstat/helper/netstathelper.cpp: -------------------------------------------------------------------------------- 1 | #include "netstathelper.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | NetstatHelper::NetstatHelper() 8 | { 9 | 10 | } 11 | 12 | KAuth::ActionReply NetstatHelper::query(const QVariantMap) 13 | { 14 | KAuth::ActionReply reply; 15 | 16 | QProcess netstat; 17 | QStringList netstatArgs("-ntuap"); 18 | qDebug() << "run" << "netstat" << netstatArgs; 19 | 20 | netstat.start("netstat", netstatArgs, QIODevice::ReadOnly); 21 | if (netstat.waitForStarted()) 22 | netstat.waitForFinished(); 23 | 24 | int exitCode(netstat.exitCode()); 25 | 26 | if(0 != exitCode) 27 | { 28 | qWarning() << "netstat command exit with code: " << exitCode; 29 | 30 | reply=KAuth::ActionReply::HelperErrorReply(exitCode); 31 | reply.addData("response", netstat.readAllStandardError()); 32 | } else { 33 | QVariantList connections = parseOutput(netstat.readAllStandardOutput()); 34 | // qDebug() << connections; 35 | reply.addData("connections", connections); 36 | } 37 | 38 | return reply; 39 | } 40 | 41 | QVariantList NetstatHelper::parseOutput(const QByteArray &netstatOutput) 42 | { 43 | QString rawOutput = netstatOutput; 44 | QStringList outputLines = rawOutput.split("\n"); 45 | 46 | QVariantList connections; 47 | 48 | int lineIdx = 0; 49 | int protIndex = 0, protSize = 0, 50 | localAddressIndex, localAddressSize, 51 | foreingAddressIndex, foreingAddressSize, 52 | stateIndex, stateSize, processIndex, processSize; 53 | 54 | for (auto line : outputLines) 55 | { 56 | // qDebug() << line; 57 | 58 | lineIdx ++; 59 | if (line.isEmpty()) 60 | continue; 61 | 62 | if (lineIdx == 1) 63 | continue; 64 | 65 | if (lineIdx == 2) { 66 | protIndex = 0; 67 | protSize = line.indexOf("Recv-Q"); 68 | 69 | localAddressIndex = line.indexOf("Local Address"); 70 | localAddressSize = line.indexOf("Foreign Address") - localAddressIndex; 71 | 72 | foreingAddressIndex = line.indexOf("Foreign Address"); 73 | foreingAddressSize = line.indexOf("State") - foreingAddressIndex; 74 | 75 | stateIndex = line.indexOf("State"); 76 | stateSize = line.indexOf("PID/Program name") - stateIndex; 77 | 78 | processIndex = line.indexOf("PID/Program name"); 79 | processSize = line.size() - processSize; 80 | 81 | continue; 82 | } 83 | 84 | QVariantList connection; 85 | 86 | connection << extractAndStrip(line, protIndex, protSize); 87 | connection << extractAndStrip(line, localAddressIndex, localAddressSize); 88 | connection << extractAndStrip(line, foreingAddressIndex, foreingAddressSize); 89 | connection << extractAndStrip(line, stateIndex, stateSize); 90 | QString pidAndProcess = extractAndStrip(line, processIndex, processSize); 91 | 92 | int slashIndex = pidAndProcess.indexOf("/"); 93 | if (slashIndex != -1) { 94 | QString pidStr = pidAndProcess.left(slashIndex); 95 | QString program = pidAndProcess.right(pidAndProcess.size() - slashIndex - 1); 96 | program = program.section(":",0,0); 97 | 98 | connection << pidStr.toInt(); 99 | connection << program; 100 | } 101 | 102 | 103 | connections.append((QVariant) connection); 104 | } 105 | 106 | return connections; 107 | } 108 | 109 | QString NetstatHelper::extractAndStrip(const QString &src, const int &index, const int &size) { 110 | QString str = src.mid(index, size); 111 | str.replace(" ", ""); 112 | return str; 113 | } 114 | 115 | KAUTH_HELPER_MAIN("org.nxos.netstat", NetstatHelper) 116 | -------------------------------------------------------------------------------- /plugins/netstat/helper/netstathelper.h: -------------------------------------------------------------------------------- 1 | #ifndef NETSTATHELPER_H 2 | #define NETSTATHELPER_H 3 | 4 | #include 5 | #include 6 | 7 | using namespace KAuth; 8 | class NetstatHelper : public QObject 9 | { 10 | Q_OBJECT 11 | public: 12 | NetstatHelper(); 13 | 14 | public Q_SLOTS: 15 | ActionReply query(const QVariantMap); 16 | 17 | private: 18 | QVariantList parseOutput(const QByteArray &netstatOutput); 19 | QString extractAndStrip(const QString &src,const int &index, const int &size); 20 | }; 21 | 22 | #endif // NETSTATHELPER_H 23 | -------------------------------------------------------------------------------- /plugins/netstat/helper/org.nxos.netstat.actions: -------------------------------------------------------------------------------- 1 | [Domain] 2 | Name=NXOS Firewall KCM netstat utils 3 | Icon=network-card 4 | URL= 5 | 6 | [org.nxos.netstat.query] 7 | Name=Read connections 8 | Description=Get system open connections. 9 | Policy=yes 10 | Persistence=session 11 | -------------------------------------------------------------------------------- /plugins/netstat/netstatclient.cpp: -------------------------------------------------------------------------------- 1 | #include "netstatclient.h" 2 | 3 | NetstatClient::NetstatClient(QObject *parent) : QObject(parent), m_connections(new ConnectionsModel(this)) 4 | { 5 | } 6 | 7 | ConnectionsModel *NetstatClient::connections() 8 | { 9 | return m_connections; 10 | } 11 | -------------------------------------------------------------------------------- /plugins/netstat/netstatclient.h: -------------------------------------------------------------------------------- 1 | #ifndef NETSTATCLIENT_H 2 | #define NETSTATCLIENT_H 3 | 4 | #include 5 | 6 | #include "conectionsmodel.h" 7 | 8 | class NetstatClient : public QObject 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | explicit NetstatClient(QObject *parent = nullptr); 14 | 15 | Q_INVOKABLE ConnectionsModel * connections(); 16 | signals: 17 | 18 | public slots: 19 | 20 | protected: 21 | ConnectionsModel * m_connections; 22 | }; 23 | 24 | #endif // NETSTATCLIENT_H 25 | -------------------------------------------------------------------------------- /plugins/netstat/netstatplugin.cpp: -------------------------------------------------------------------------------- 1 | #include "netstatplugin.h" 2 | 3 | #include 4 | 5 | #include "netstatclient.h" 6 | #include "conectionsmodel.h" 7 | 8 | void NetstatPlugin::registerTypes(const char *uri) 9 | { 10 | Q_ASSERT(uri == QLatin1String("org.nomad.netstat")); 11 | 12 | qmlRegisterType(uri, 1, 0, "NetstatClient"); 13 | qmlRegisterUncreatableType (uri, 1,9, "ConnectionsModel", "Use the NetstatClient"); 14 | 15 | int exitCode = QProcess::execute("netstat", {"--version"}); 16 | if (exitCode == -2) { // could not execute file 17 | qWarning() << "netstat is not installed or not in the PATH, please configure system."; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /plugins/netstat/netstatplugin.h: -------------------------------------------------------------------------------- 1 | #ifndef NETSTATPLUGIN_H 2 | #define NETSTATPLUGIN_H 3 | 4 | #include 5 | 6 | class NetstatPlugin : public QQmlExtensionPlugin 7 | { 8 | Q_OBJECT 9 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") 10 | 11 | public: 12 | virtual void registerTypes(const char *uri) override; 13 | }; 14 | 15 | #endif // NETSTATPLUGIN_H 16 | -------------------------------------------------------------------------------- /plugins/netstat/qmldir: -------------------------------------------------------------------------------- 1 | module org.nomad.netstat 2 | plugin nomad_netstat_plugin 3 | -------------------------------------------------------------------------------- /plugins/ufw/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(helper) 2 | 3 | find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS 4 | Quick 5 | Xml 6 | X11Extras 7 | ) 8 | 9 | find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS 10 | Plasma 11 | PlasmaQuick 12 | I18n 13 | Declarative 14 | Auth 15 | Config 16 | KDELibs4Support 17 | ) 18 | 19 | 20 | set(nomad_ufw_plugin_SRCS 21 | ufwplugin.cpp 22 | ufwclient.cpp 23 | blocker.cpp 24 | profile.cpp 25 | rule.cpp 26 | types.cpp 27 | appprofiles.cpp 28 | rulelistmodel.cpp 29 | loglistmodel.cpp 30 | rulewrapper.cpp 31 | qmldir 32 | ) 33 | 34 | 35 | add_library(nomad_ufw_plugin SHARED ${nomad_ufw_plugin_SRCS}) 36 | target_link_libraries(nomad_ufw_plugin 37 | Qt5::Core 38 | Qt5::Quick 39 | Qt5::Xml 40 | Qt5::X11Extras 41 | KF5::CoreAddons 42 | KF5::ConfigCore 43 | KF5::Auth 44 | KF5::I18n 45 | KF5::KDELibs4Support) 46 | 47 | set(INSTALL_PATH ${QML_INSTALL_DIR}/org/nomad/ufw) 48 | 49 | install(TARGETS nomad_ufw_plugin DESTINATION ${INSTALL_PATH}) 50 | install(FILES qmldir DESTINATION ${INSTALL_PATH}) 51 | -------------------------------------------------------------------------------- /plugins/ufw/appprofiles.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * UFW KControl Module 3 | * 4 | * Copyright 2011 Craig Drummond 5 | * 6 | * ---- 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; see the file COPYING. If not, write to 20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 | * Boston, MA 02110-1301, USA. 22 | */ 23 | 24 | #include "appprofiles.h" 25 | #include 26 | #include 27 | #include 28 | 29 | namespace UFW 30 | { 31 | 32 | namespace AppProfiles 33 | { 34 | 35 | Entry::Entry(const QString &n, const QString &p) 36 | : name(n), ports(p) 37 | { 38 | ports.replace('|', ' '); 39 | } 40 | 41 | /* TODO: Find a way to fix this. 42 | this feels really wrong. a Function that returns a reference 43 | for a static variable created inside of it. 44 | */ 45 | const QList & get() 46 | { 47 | static QList profiles; 48 | static bool init=false; 49 | 50 | if(!init) 51 | { 52 | static const char * constProfileDir="/etc/ufw/applications.d/"; 53 | 54 | QStringList files(QDir(constProfileDir).entryList()); 55 | QStringList::ConstIterator it(files.constBegin()), 56 | end(files.constEnd()); 57 | 58 | for(; it!=end; ++it) 59 | if((*it)!="." && (*it)!="..") 60 | { 61 | KConfig cfg(constProfileDir+(*it), KConfig::SimpleConfig); 62 | QStringList groups(cfg.groupList()); 63 | QStringList::ConstIterator gIt(groups.constBegin()), 64 | gEnd(groups.constEnd()); 65 | 66 | for(; gIt!=gEnd; ++gIt) 67 | { 68 | QString ports(cfg.group(*gIt).readEntry("ports", QString())); 69 | 70 | if(!ports.isEmpty() && !profiles.contains(*gIt)) 71 | profiles.append(Entry(*gIt, ports)); 72 | } 73 | } 74 | qSort(profiles); 75 | } 76 | 77 | return profiles; 78 | } 79 | 80 | Entry get(const QString &name) 81 | { 82 | // This feels *so* wrong. 83 | for(const auto entry : qAsConst(get())) { 84 | if (entry.name == name) { 85 | return entry; 86 | } 87 | } 88 | return Entry({}); 89 | } 90 | 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /plugins/ufw/appprofiles.h: -------------------------------------------------------------------------------- 1 | #ifndef UFW_APP_PROFILES_H 2 | #define UFW_APP_PROFILES_H 3 | 4 | /* 5 | * UFW KControl Module 6 | * 7 | * Copyright 2011 Craig Drummond 8 | * 9 | * ---- 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program; see the file COPYING. If not, write to 23 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301, USA. 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | namespace UFW 31 | { 32 | 33 | namespace AppProfiles 34 | { 35 | 36 | struct Entry 37 | { 38 | Entry(const QString &n, const QString &p=QString()); 39 | bool operator<(const Entry &o) const { return name.localeAwareCompare(o.name)<0; } 40 | bool operator==(const Entry &o) const { return name==o.name; } 41 | QString name; 42 | QString ports; 43 | // Types::Protocol protocol; 44 | }; 45 | 46 | extern const QList & get(); 47 | extern Entry get(const QString &name); 48 | 49 | } 50 | 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /plugins/ufw/blocker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * UFW KControl Module 3 | * 4 | * Copyright 2011 Craig Drummond 5 | * 6 | * ---- 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; see the file COPYING. If not, write to 20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 | * Boston, MA 02110-1301, USA. 22 | */ 23 | 24 | #include "blocker.h" 25 | #include 26 | 27 | namespace UFW 28 | { 29 | 30 | void Blocker::add(QObject *object) 31 | { 32 | object->removeEventFilter(this); 33 | object->installEventFilter(this); 34 | } 35 | 36 | bool Blocker::eventFilter(QObject *object, QEvent *event) 37 | { 38 | if(active && 39 | (QEvent::MouseButtonPress==event->type() || QEvent::MouseButtonRelease==event->type() || 40 | QEvent::MouseButtonDblClick==event->type() || 41 | QEvent::KeyPress==event->type() || QEvent::KeyRelease==event->type())) 42 | return true; 43 | return QObject::eventFilter(object, event); 44 | } 45 | 46 | } 47 | 48 | #include "blocker.moc" 49 | -------------------------------------------------------------------------------- /plugins/ufw/blocker.h: -------------------------------------------------------------------------------- 1 | #ifndef UFW_BLOCKER_H 2 | #define UFW_BLOCKER_H 3 | 4 | /* 5 | * UFW KControl Module 6 | * 7 | * Copyright 2011 Craig Drummond 8 | * 9 | * ---- 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program; see the file COPYING. If not, write to 23 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301, USA. 25 | */ 26 | 27 | #include 28 | 29 | namespace UFW 30 | { 31 | 32 | class Blocker : public QObject 33 | { 34 | Q_OBJECT 35 | 36 | public: 37 | 38 | Blocker(QObject *parent) : QObject(parent), active(false) { } 39 | virtual ~Blocker() { } 40 | 41 | void add(QObject *object); 42 | bool eventFilter(QObject *object, QEvent *event); 43 | void setActive(bool b) { active=b; } 44 | bool isActive() const { return active; } 45 | 46 | private: 47 | 48 | bool active; 49 | }; 50 | 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /plugins/ufw/helper/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Find includes in corresponding build directories 2 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 3 | include_directories(${CMAKE_BINARY_DIR}) 4 | 5 | # Instruct CMake to run moc automatically when needed. 6 | set(CMAKE_AUTOMOC ON) 7 | 8 | find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS 9 | Quick 10 | X11Extras 11 | ) 12 | 13 | 14 | find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS 15 | I18n 16 | Auth 17 | ) 18 | 19 | 20 | set(ufw_plugin_helper_SRCS helper.cpp ) 21 | add_executable(nomad_ufw_plugin_helper ${ufw_plugin_helper_SRCS}) 22 | 23 | # set_target_properties(kcm_ufw_helper PROPERTIES OUTPUT_NAME kcm_ufw_helper) 24 | target_link_libraries(nomad_ufw_plugin_helper Qt5::Core KF5::Auth) 25 | if (IS_ABSOLUTE "${LIBEXEC_INSTALL_DIR}") 26 | set(UFW_PLUGIN_HELPER_PATH ${LIBEXEC_INSTALL_DIR}/nomad_ufw_plugin_helper.py) 27 | else() 28 | set(UFW_PLUGIN_HELPER_PATH ${CMAKE_INSTALL_PREFIX}/${LIBEXEC_INSTALL_DIR}/nomad_ufw_plugin_helper.py) 29 | endif() 30 | configure_file(kcm_ufw_helper.py.cmake ${CMAKE_BINARY_DIR}/nomad_ufw_plugin_helper.py) 31 | configure_file(ufw_helper_config.h.cmake ${CMAKE_BINARY_DIR}/ufw_helper_config.h) 32 | 33 | kauth_install_actions(org.nomad.ufw org.nomad.ufw.actions) 34 | install(TARGETS nomad_ufw_plugin_helper DESTINATION ${KAUTH_HELPER_INSTALL_DIR}) 35 | kauth_install_helper_files(nomad_ufw_plugin_helper org.nomad.ufw root) 36 | 37 | # install(TARGETS kcm_ufw_helper DESTINATION ${LIBEXEC_INSTALL_DIR}) 38 | install(PROGRAMS ${CMAKE_BINARY_DIR}/nomad_ufw_plugin_helper.py DESTINATION ${LIBEXEC_INSTALL_DIR}) 39 | 40 | # configure_file(org.kde.ufw.service.cmake ${CMAKE_CURRENT_BINARY_DIR}/session/org.kde.ufw.service) 41 | # install(FILES ${CMAKE_CURRENT_BINARY_DIR}/session/org.kde.ufw.service DESTINATION ${DBUS_SERVICES_INSTALL_DIR}) 42 | install(FILES defaults DESTINATION ${DATA_INSTALL_DIR}/kcm_ufw) 43 | -------------------------------------------------------------------------------- /plugins/ufw/helper/defaults: -------------------------------------------------------------------------------- 1 | incoming=allow 2 | outgoing=allow 3 | loglevel=off 4 | ipv6=false 5 | modules=nf_conntrack_netbios_ns nf_conntrack_pptp nf_nat_pptp 6 | -------------------------------------------------------------------------------- /plugins/ufw/helper/helper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * UFW KControl Module 3 | * 4 | * Copyright 2011 Craig Drummond 5 | * 6 | * ---- 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; see the file COPYING. If not, write to 20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 | * Boston, MA 02110-1301, USA. 22 | */ 23 | 24 | #include "helper.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | 39 | #include "ufw_helper_config.h" 40 | 41 | namespace UFW 42 | { 43 | 44 | #define FILE_PERMS 0644 45 | #define DIR_PERMS 0755 46 | #define KCM_UFW_DIR "/etc/kcm_ufw" 47 | #define PROFILE_EXTENSION ".ufw" 48 | #define LOG_FILE "/var/log/ufw.log" 49 | 50 | static void setPermissions(const QString &f, int perms) 51 | { 52 | // 53 | // Clear any umask before setting file perms 54 | mode_t oldMask(umask(0000)); 55 | ::chmod(QFile::encodeName(f).constData(), perms); 56 | // Reset umask 57 | ::umask(oldMask); 58 | } 59 | 60 | static void checkFolder() 61 | { 62 | QDir d(KCM_UFW_DIR); 63 | 64 | if(!d.exists()) 65 | { 66 | d.mkpath(KCM_UFW_DIR); 67 | setPermissions(d.absolutePath(), DIR_PERMS); 68 | } 69 | } 70 | 71 | ActionReply Helper::query(const QVariantMap &args) 72 | { 73 | qDebug() << __FUNCTION__; 74 | ActionReply reply=args["defaults"].toBool() 75 | ? run({"--status", "--defaults", "--list", "--modules"}, "query") 76 | : run({"--status", "--list"}, "query"); 77 | 78 | if(args["profiles"].toBool()) { 79 | QDir dir(KCM_UFW_DIR); 80 | QStringList profiles=dir.entryList({"*" PROFILE_EXTENSION }); 81 | QMap data; 82 | for (const QString &profile : profiles) { 83 | QFile f(dir.canonicalPath()+QChar('/')+profile); 84 | if (f.open(QIODevice::ReadOnly)) { 85 | data.insert(profile, f.readAll()); 86 | } 87 | } 88 | reply.addData("profiles", data); 89 | } 90 | 91 | return reply; 92 | } 93 | 94 | ActionReply Helper::viewlog(const QVariantMap &args) 95 | { 96 | qDebug() << __FUNCTION__; 97 | 98 | QString lastLine=args["lastLine"].toString(), 99 | logFile=args["logFile"].toString(); 100 | QFile file(logFile.isEmpty() ? QLatin1String(LOG_FILE) : logFile); 101 | ActionReply reply; 102 | 103 | if(file.open(QIODevice::ReadOnly|QIODevice::Text)) 104 | { 105 | QStringList lines; 106 | while (!file.atEnd()) 107 | { 108 | QString line(file.readLine()); 109 | 110 | if(line.contains(" [UFW ")) 111 | { 112 | if(!lastLine.isEmpty() && line==lastLine) 113 | { 114 | lines.clear(); 115 | continue; 116 | } 117 | lines.append(line); 118 | } 119 | } 120 | 121 | reply.addData("lines", lines); 122 | } 123 | else 124 | { 125 | reply=ActionReply::HelperErrorReply(STATUS_OPERATION_FAILED); 126 | } 127 | 128 | return reply; 129 | } 130 | 131 | ActionReply Helper::modify(const QVariantMap &args) 132 | { 133 | qDebug() << __FUNCTION__; 134 | QString cmd=args["cmd"].toString(); 135 | 136 | // QProcess converts its args using QString().toLocal8Bit()!!!, so use UTF-8 codec!!! 137 | QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); 138 | 139 | if("setStatus"==cmd) 140 | return setStatus(args, cmd); 141 | else if("addRules"==cmd) 142 | return addRules(args, cmd); 143 | else if("removeRule"==cmd) 144 | return removeRule(args, cmd); 145 | else if("moveRule"==cmd) 146 | return moveRule(args, cmd); 147 | else if("editRule"==cmd) 148 | return editRule(args, cmd); 149 | // else if("editRuleDescr"==cmd) 150 | // return editRuleDescr(args, cmd); 151 | else if("reset"==cmd) 152 | return reset(cmd); 153 | else if("setDefaults"==cmd) 154 | return setDefaults(args, cmd); 155 | else if("setModules"==cmd) 156 | return setModules(args, cmd); 157 | else if("setProfile"==cmd) 158 | return setProfile(args, cmd); 159 | else if("saveProfile"==cmd) 160 | return saveProfile(args, cmd); 161 | else if("deleteProfile"==cmd) 162 | return deleteProfile(args, cmd); 163 | 164 | ActionReply reply=ActionReply::HelperErrorReply(STATUS_INVALID_CMD); 165 | return reply; 166 | } 167 | 168 | ActionReply Helper::setStatus(const QVariantMap &args, const QString &cmd) 169 | { 170 | const QString enabled = args["status"].toBool() ? "true" : "false"; 171 | 172 | return run({"--setEnabled=" + enabled}, 173 | {"--status"}, cmd); 174 | } 175 | 176 | ActionReply Helper::setDefaults(const QVariantMap &args, const QString &cmd) 177 | { 178 | QStringList query({"--defaults"}); 179 | if (args["ipv6"].toBool()) 180 | query.append("--list"); 181 | 182 | const QString defaults = args["xml"].toString(); 183 | 184 | return run({"--setDefaults="+defaults}, 185 | query, cmd); 186 | } 187 | 188 | ActionReply Helper::setModules(const QVariantMap &args, const QString &cmd) 189 | { 190 | return run({"--setModules="+args["xml"].toString()}, 191 | {"--modules"}, cmd); 192 | } 193 | 194 | ActionReply Helper::setProfile(const QVariantMap &args, const QString &cmd) 195 | { 196 | QStringList cmdArgs; 197 | 198 | if(args.contains("ruleCount")) 199 | { 200 | unsigned int count=args["ruleCount"].toUInt(); 201 | 202 | cmdArgs.append("--clearRules"); 203 | for(unsigned int i=0; i < count; ++i) { 204 | const QString argument = args["rule"+QString::number(i)].toString(); 205 | cmdArgs.append("--add="+argument); 206 | } 207 | } 208 | 209 | if(args.contains("defaults")) { 210 | cmdArgs << "--setDefaults="+args["defaults"].toString(); 211 | } 212 | if(args.contains("modules")) { 213 | cmdArgs << "--setModules="+args["modules"].toString(); 214 | } 215 | 216 | if(cmdArgs.isEmpty()) { 217 | return ActionReply::HelperErrorReply(STATUS_INVALID_ARGUMENTS); 218 | } 219 | 220 | checkFolder(); 221 | return run(cmdArgs, {"--status", "--defaults", "--list", "--modules"}, cmd); 222 | } 223 | 224 | ActionReply Helper::saveProfile(const QVariantMap &args, const QString &cmd) 225 | { 226 | qDebug() << __FUNCTION__ << args; 227 | 228 | QString name(args["name"].toString()), 229 | xml(args["xml"].toString()); 230 | ActionReply reply; 231 | 232 | if(name.isEmpty() || xml.isEmpty()) 233 | { 234 | reply=ActionReply::HelperErrorReply(STATUS_INVALID_ARGUMENTS); 235 | } 236 | else 237 | { 238 | checkFolder(); 239 | 240 | QFile f(QString(KCM_UFW_DIR)+"/"+name+PROFILE_EXTENSION); 241 | 242 | if(f.open(QIODevice::WriteOnly)) 243 | { 244 | QTextStream(&f) << xml; 245 | f.close(); 246 | setPermissions(f.fileName(), FILE_PERMS); 247 | } 248 | else 249 | { 250 | reply=ActionReply::HelperErrorReply(STATUS_OPERATION_FAILED); 251 | } 252 | } 253 | 254 | reply.addData("cmd", cmd); 255 | reply.addData("name", name); 256 | reply.addData("profiles", QDir(KCM_UFW_DIR).entryList({"*" PROFILE_EXTENSION })); 257 | return reply; 258 | } 259 | 260 | ActionReply Helper::deleteProfile(const QVariantMap &args, const QString &cmd) 261 | { 262 | qDebug() << __FUNCTION__ << args; 263 | 264 | QString name(args["name"].toString()); 265 | ActionReply reply; 266 | 267 | if(name.isEmpty()) 268 | { 269 | reply=ActionReply::HelperErrorReply(STATUS_INVALID_ARGUMENTS); 270 | } 271 | else if(!QFile::remove(QString(KCM_UFW_DIR)+"/"+name+PROFILE_EXTENSION)) 272 | { 273 | reply=ActionReply::HelperErrorReply(STATUS_OPERATION_FAILED); 274 | } 275 | 276 | reply.addData("cmd", cmd); 277 | reply.addData("name", name); 278 | reply.addData("profiles", QDir(KCM_UFW_DIR).entryList({"*" PROFILE_EXTENSION })); 279 | return reply; 280 | } 281 | 282 | ActionReply Helper::addRules(const QVariantMap &args, const QString &cmd) 283 | { 284 | unsigned int count=args["count"].toUInt(); 285 | 286 | if(count>0) 287 | { 288 | QStringList cmdArgs; 289 | 290 | for(unsigned int i=0; i 8 | * 9 | * ---- 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program; see the file COPYING. If not, write to 23 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301, USA. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | class QStringList; 32 | class QByteArray; 33 | 34 | using namespace KAuth; 35 | 36 | namespace UFW 37 | { 38 | 39 | class LogLister; 40 | 41 | class Helper : public QObject 42 | { 43 | Q_OBJECT 44 | 45 | public: 46 | 47 | enum Status 48 | { 49 | STATUS_OK, 50 | STATUS_INVALID_CMD = -100, 51 | STATUS_INVALID_ARGUMENTS = -101, 52 | STATUS_OPERATION_FAILED = -102, 53 | }; 54 | 55 | public Q_SLOTS: 56 | 57 | ActionReply query(const QVariantMap &args); 58 | ActionReply viewlog(const QVariantMap &args); 59 | ActionReply modify(const QVariantMap &args); 60 | 61 | private: 62 | 63 | ActionReply setStatus(const QVariantMap &args, const QString &cmd); 64 | ActionReply setDefaults(const QVariantMap &args, const QString &cmd); 65 | ActionReply setModules(const QVariantMap &args, const QString &cmd); 66 | ActionReply setProfile(const QVariantMap &args, const QString &cmd); 67 | ActionReply saveProfile(const QVariantMap &args, const QString &cmd); 68 | ActionReply deleteProfile(const QVariantMap &args, const QString &cmd); 69 | ActionReply addRules(const QVariantMap &args, const QString &cmd); 70 | ActionReply removeRule(const QVariantMap &args, const QString &cmd); 71 | ActionReply moveRule(const QVariantMap &args, const QString &cmd); 72 | ActionReply editRule(const QVariantMap &args, const QString &cmd); 73 | // ActionReply editRuleDescr(const QVariantMap &args, const QString &cmd); 74 | ActionReply reset(const QString &cmd); 75 | ActionReply run(const QStringList &args, const QString &cmd); 76 | ActionReply run(const QStringList &args, const QStringList &second, const QString &cmd); 77 | 78 | private: 79 | 80 | LogLister *lister; 81 | }; 82 | 83 | } 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /plugins/ufw/helper/kcm_ufw_helper.py.cmake: -------------------------------------------------------------------------------- 1 | #!@PYTHON_EXECUTABLE@ 2 | 3 | # 4 | # UFW KControl Module 5 | # 6 | # Copyright 2011 Craig Drummond 7 | # 8 | #------------------------------------------------------------------- 9 | # Some of the code here is taken/inspired from ufw-frontends, 10 | # Copyright notice for this follows... 11 | #------------------------------------------------------------------- 12 | # 13 | # frontend.py: Base frontend for ufw 14 | # 15 | # Copyright (C) 2010 Darwin M. Bautista 16 | # 17 | # This program is free software: you can redistribute it and/or modify 18 | # it under the terms of the GNU General Public License as published by 19 | # the Free Software Foundation, either version 3 of the License, or 20 | # (at your option) any later version. 21 | # 22 | # This program is distributed in the hope that it will be useful, 23 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | # GNU General Public License for more details. 26 | # 27 | # You should have received a copy of the GNU General Public License 28 | # along with this program. If not, see . 29 | 30 | import os 31 | import sys 32 | 33 | import locale 34 | import gettext 35 | 36 | import getopt 37 | import shutil 38 | import hashlib 39 | import io 40 | 41 | from xml.etree import ElementTree as etree 42 | from copy import deepcopy 43 | 44 | import ufw.common 45 | import ufw.frontend 46 | from ufw.util import valid_address 47 | from ufw.common import UFWRule 48 | 49 | ANY_ADDR = '0.0.0.0/0' 50 | ANY_PORT = 'any' 51 | ANY_PROTOCOL = 'any' 52 | OLD_DESCR_FILE = "/etc/ufw/descriptions" 53 | DESCR_FILE = "/etc/kcm_ufw/descriptions" 54 | DEFAULTS_FILE = "@DATA_INSTALL_DIR@/kcm_ufw/defaults" 55 | 56 | ERROR_FAILED_TO_SET_STATUS = -1 57 | ERROR_INVALID_INDEX = -2 58 | ERROR_INVALID_XML_NO_RULE = -3 59 | ERROR_INVALID_XML_NO_ACTION_XML = -4 60 | ERROR_INVALID_XML_NO_DEFAULTS = -5 61 | ERROR_INVALID_XML_NO_MODULES = -6 62 | 63 | 64 | class UFWFrontend(ufw.frontend.UFWFrontend): 65 | 66 | def __init__(self, dryrun): 67 | ufw.frontend.UFWFrontend.__init__(self, dryrun) 68 | # Compatibility for ufw 0.31 69 | # This is a better way of handling method renames instead of putting 70 | # try/except blocks all over the whole application code 71 | # Ref: http://code.google.com/p/ufw-frontends/issues/detail?id=20 72 | try: 73 | self.backend.get_default_policy 74 | except AttributeError: 75 | self.backend.get_default_policy = self.backend._get_default_policy 76 | try: 77 | self.backend._is_enabled 78 | except AttributeError: 79 | self.backend._is_enabled = self.backend.is_enabled 80 | 81 | 82 | def localizeUfw(): 83 | # Ref: http://code.google.com/p/ufw-frontends/issues/detail?id=19 84 | locale.setlocale(locale.LC_ALL, 'C') 85 | gettext.install(ufw.common.programName) 86 | 87 | #define looad descriptions file 88 | # descrsChanged=False 89 | # def moveOldDescrFile(): 90 | # try: 91 | # if os.path.exists(OLD_DESCR_FILE) and os.path.isfile(OLD_DESCR_FILE): 92 | # shutil.move(OLD_DESCR_FILE, DESCR_FILE) 93 | # except Exception as e: 94 | # return # Old file does not exist, or is not a file!... 95 | # 96 | # def loadDescriptions(): 97 | # moveOldDescrFile(); 98 | # try: 99 | # global descrs 100 | # descrs={"a":"b"} 101 | # descrData=open(DESCR_FILE).read() 102 | # descrs=eval(descrData) 103 | # except Exception as e: 104 | # return 105 | # 106 | # def removeDescriptions(): 107 | # try: 108 | # os.remove(DESCR_FILE) 109 | # descrsChanged=False 110 | # except Exception as e: 111 | # return 112 | # 113 | # def saveDescriptions(): 114 | # global descrsChanged 115 | # if descrsChanged: 116 | # try: 117 | # if ("a" in descrs): 118 | # del descrs["a"] 119 | # if len(descrs)>0: 120 | # descrFile = open(DESCR_FILE, 'w') 121 | # descrFile.write(repr(descrs)) 122 | # descrsChanged=False 123 | # else: 124 | # removeDescriptions() 125 | # except Exception as e: 126 | # return 127 | # 128 | # def getDescription(hashStr): 129 | # if (hashStr in descrs): 130 | # return descrs[hashStr] 131 | # return '' 132 | # 133 | # def removeDescription(hashStr): 134 | # if (hashStr in descrs): 135 | # del descrs[hashStr] 136 | # global descrsChanged 137 | # descrsChanged=True 138 | # 139 | # def updateDescription(hashStr, descrStr): 140 | # if ((hashStr in descrs)==False) or (descrs[hashStr]!=descrStr): 141 | # removeDescription(hashStr) 142 | # descrs[hashStr]=descrStr 143 | # global descrsChanged 144 | # descrsChanged=True 145 | 146 | def loadDefaultSettings(ufw): 147 | try: 148 | defaultsFile=open(DEFAULTS_FILE) 149 | while 1: 150 | line = defaultsFile.readline() 151 | if line == '': 152 | break 153 | parts=line.split('=') 154 | if len(parts) == 2: 155 | value=parts[1].replace('\n', '') 156 | if parts[0] == 'incoming': 157 | ufw.set_default_policy(value, 'incoming') 158 | elif parts[0] == 'outgoing': 159 | ufw.set_default_policy(value, 'outgoing') 160 | elif parts[0] == 'loglevel': 161 | ufw.set_loglevel(value) 162 | elif parts[0] == 'ipv6': 163 | ufw.backend.set_default(ufw.backend.files['defaults'], 'IPV6', value.lower()) 164 | elif parts[0] == 'modules': 165 | ufw.backend.set_default(ufw.backend.files['defaults'], 'IPT_MODULES', '"' + value + '"') 166 | except Exception as e: 167 | return 168 | 169 | # Localise UFW, and init the 'frontend' 170 | localizeUfw() 171 | ufw=UFWFrontend(False) 172 | 173 | def getProtocol(rule): 174 | """Determine protocol of rule. 175 | Taken from ufw.parser.UFWCommandRule.parse 176 | """ 177 | # Determine src type 178 | if rule.src == ANY_ADDR: 179 | from_type = 'any' 180 | else: 181 | from_type = ('v6' if valid_address(rule.src, '6') else 'v4') 182 | # Determine dst type 183 | if rule.dst == ANY_ADDR: 184 | to_type = 'any' 185 | else: 186 | to_type = ('v6' if valid_address(rule.dst, '6') else 'v4') 187 | # Figure out the type of rule (IPv4, IPv6, or both) 188 | if from_type == ANY_PROTOCOL and to_type == ANY_PROTOCOL: 189 | protocol = 'both' 190 | elif from_type != ANY_PROTOCOL and to_type != ANY_PROTOCOL and from_type != to_type: 191 | err_msg = _("Mixed IP versions for 'from' and 'to'") 192 | raise ufw.common.UFWError(err_msg) 193 | elif from_type != ANY_PROTOCOL: 194 | protocol = from_type 195 | elif to_type != ANY_PROTOCOL: 196 | protocol = to_type 197 | return protocol 198 | 199 | def insertRule(ufw, rule, protocol=None): 200 | if protocol is None: 201 | protocol = getProtocol(rule) 202 | rule = rule.dup_rule() 203 | # Fix any inconsistency 204 | if rule.sapp or rule.dapp: 205 | rule.set_protocol(ANY_PROTOCOL) 206 | if rule.sapp: 207 | rule.sport = rule.sapp 208 | if rule.dapp: 209 | rule.dport = rule.dapp 210 | # If trying to insert beyond the end, just set position to 0 211 | if rule.position and not ufw.backend.get_rule_by_number(rule.position): 212 | rule.set_position(0) 213 | ufw.set_rule(rule, protocol) 214 | # Reset the positions of the recently inserted rule(s) 215 | if rule.position: 216 | s = rule.position - 1 217 | e = rule.position + 1 218 | for r in ufw.backend.get_rules()[s:e]: 219 | r.set_position(0) 220 | return rule 221 | 222 | def getRulesList(ufw): 223 | app_rules = [] 224 | for i, r in enumerate(ufw.backend.get_rules()): 225 | if r.dapp or r.sapp: 226 | t = r.get_app_tuple() 227 | if t in app_rules: 228 | continue 229 | else: 230 | app_rules.append(t) 231 | yield (i, r) 232 | 233 | def encodeText(str): 234 | str=str.replace("&", "&") 235 | str=str.replace("<", "<") 236 | str=str.replace("\"", """) 237 | str=str.replace(">", ">") 238 | return str 239 | 240 | def ruleDetails(rule): 241 | xmlStr = io.StringIO() 242 | xmlStr.write("action=\"") 243 | xmlStr.write(rule.action.lower()) 244 | xmlStr.write("\" direction=\"") 245 | xmlStr.write(rule.direction.lower()) 246 | xmlStr.write("\" dapp=\"") 247 | xmlStr.write(rule.dapp) 248 | xmlStr.write("\" sapp=\"") 249 | xmlStr.write(rule.sapp) 250 | xmlStr.write("\" dport=\"") 251 | xmlStr.write(rule.dport) 252 | xmlStr.write("\" sport=\"") 253 | xmlStr.write(rule.sport) 254 | xmlStr.write("\" protocol=\"") 255 | xmlStr.write(rule.protocol.lower()) 256 | xmlStr.write("\" dst=\"") 257 | xmlStr.write(rule.dst) 258 | xmlStr.write("\" src=\"") 259 | xmlStr.write(rule.src) 260 | xmlStr.write("\" interface_in=\"") 261 | xmlStr.write(rule.interface_in) 262 | xmlStr.write("\" interface_out=\"") 263 | xmlStr.write(rule.interface_out) 264 | xmlStr.write("\" v6=\"") 265 | if rule.v6: 266 | xmlStr.write('True') 267 | else: 268 | xmlStr.write('False') 269 | return xmlStr.getvalue() 270 | 271 | # def detailsHash(details): 272 | # ruleHash = hashlib.md5() 273 | # ruleHash.update(details.encode('utf-8')) 274 | # return ruleHash.hexdigest() 275 | 276 | # Convert a rule to an XML string... 277 | def toXml(rule, xmlStr): 278 | xmlStr.write("") 293 | 294 | # Create rule from XML... 295 | def fromXml(str): 296 | elem = etree.XML(str) 297 | if elem.tag != 'rule': 298 | error("ERROR: Invalid XML, expected \'rule\' element", ERROR_INVALID_XML_NO_RULE) 299 | action=elem.get('action', '').lower() 300 | if action == '': 301 | error("ERROR: Invalid XML, no action specified", ERROR_INVALID_XML_NO_ACTION_XML) 302 | protocol=elem.get('protocol', ANY_PROTOCOL).lower() 303 | rule = UFWRule(action, protocol) 304 | rule.position=int(elem.get('position', 0)) 305 | rule.direction=elem.get('direction', 'in').lower() 306 | rule.dapp=elem.get('dapp', '') 307 | rule.sapp=elem.get('sapp', '') 308 | rule.dport=elem.get('dport', ANY_PORT) 309 | rule.sport=elem.get('sport', ANY_PORT) 310 | rule.dst=elem.get('dst', ANY_ADDR) 311 | rule.src=elem.get('src', ANY_ADDR) 312 | rule.interface_in=elem.get('interface_in', '') 313 | rule.interface_out=elem.get('interface_out', '') 314 | rule.logtype=elem.get('logtype', '').lower() 315 | rule.v6=elem.get('v6', 'False').lower() == "true" 316 | return rule 317 | 318 | def getStatus(ufw, xmlStr): 319 | xmlStr.write("") 325 | 326 | def setEnabled(ufw, status): 327 | if status.lower() == "false": 328 | stat=False 329 | else: 330 | stat=True 331 | if stat != ufw.backend._is_enabled(): 332 | ufw.set_enabled(stat) 333 | if ufw.backend._is_enabled() != stat: 334 | error("ERROR: Failed to set UFW status", ERROR_FAILED_TO_SET_STATUS) 335 | 336 | def getDefaults(ufw, xmlStr): 337 | conf = ufw.backend.defaults 338 | xmlStr.write("") 347 | 348 | def setDefaults(ufw, xml): 349 | elem = etree.XML(xml) 350 | if elem.tag != 'defaults': 351 | error("ERROR: Invalid XML, expected \'defaults\' element", ERROR_INVALID_XML_NO_DEFAULTS) 352 | enabled=ufw.backend._is_enabled() 353 | if enabled: 354 | ufw.set_enabled(False) 355 | ipv6=elem.get('ipv6', '').lower() 356 | if ipv6 != '': 357 | del ufw 358 | ufw=UFWFrontend(False) 359 | ufw.backend.set_default(ufw.backend.files['defaults'], 'IPV6', ipv6) 360 | del ufw 361 | ufw=UFWFrontend(False) 362 | policy=elem.get('incoming', '').lower() 363 | if policy != '': 364 | ufw.set_default_policy(policy, 'incoming') 365 | policy=elem.get('outgoing', '').lower() 366 | if policy != '': 367 | ufw.set_default_policy(policy, 'outgoing') 368 | loglevel=elem.get('loglevel', '').lower() 369 | if loglevel != '': 370 | ufw.set_loglevel(loglevel) 371 | if enabled: 372 | ufw.set_enabled(True) 373 | 374 | def getRules(ufw, xmlStr): 375 | xmlStr.write("") 376 | for i, data in enumerate(getRulesList(ufw)): 377 | idx, rule = data 378 | toXml(rule.dup_rule(), xmlStr) 379 | xmlStr.write("") 380 | 381 | # def updateRuleDescription(rule, xml): 382 | # elem=etree.XML(xml) 383 | # descr=elem.get('descr', '') 384 | # oldHashCode=elem.get('hash', '') 385 | # if descr != '': 386 | # details=ruleDetails(rule) 387 | # hashStr=detailsHash(details) 388 | # # For an update, we should be passed old hash code - if so, remove old entry... 389 | # if oldHashCode!= '': 390 | # removeDescription(oldHashCode) 391 | # updateDescription(hashStr, descr) 392 | # else: 393 | # if oldHashCode!= '': 394 | # removeDescription(oldHashCode) 395 | 396 | def addRule(ufw, xml): 397 | rule=fromXml(xml) 398 | inserted=insertRule(ufw, rule) 399 | # updateRuleDescription(inserted, xml) 400 | 401 | def updateRule(ufw, xml): 402 | rule=fromXml(xml) 403 | deleted=False 404 | try: 405 | prev=deepcopy(ufw.backend.get_rule_by_number(rule.position)) 406 | ufw.delete_rule(rule.position, True) 407 | deleted=True 408 | inserted=insertRule(ufw, rule) 409 | deleted=False 410 | # updateRuleDescription(inserted, xml) 411 | except Exception as e: 412 | if deleted: 413 | insertRule(ufw, prev) 414 | 415 | # def updateRuleDescr(ufw, xml): 416 | # rule=fromXml(xml) 417 | # details=ruleDetails(rule) 418 | # hashStr=detailsHash(details) 419 | # updateRuleDescription(rule, xml) 420 | 421 | # Remove a rule. Index is either; just the index, or : 422 | def removeRule(ufw, index): 423 | parts=index.split(':') 424 | try: 425 | if 2==len(parts): 426 | idx=int(parts[0]) 427 | else: 428 | idx=int(index) 429 | if idx<1 or idx>(ufw.backend.get_rules_count(False)+ufw.backend.get_rules_count(True)): 430 | error("ERROR: Invalid index", ERROR_INVALID_INDEX) 431 | # if 2==len(parts): 432 | # removeDescription(parts[1]) 433 | # else: 434 | # rule=ufw.backend.get_rule_by_number(index) 435 | # if rule: 436 | # details=ruleDetails(rule) 437 | # hashStr=detailsHash(details) 438 | # removeDescription(hashStr) 439 | ufw.delete_rule(idx, True) 440 | #except ufw.common.UFWError as e: 441 | #error("ERROR: UFW error", e.value) 442 | except ValueError: 443 | error("ERROR: Invalid input type", ERROR_INVALID_INDEX) 444 | 445 | def moveRule(ufw, indexes): 446 | idx=indexes.split(':') 447 | if 2!= len(idx): 448 | error("ERROR: Invalid number of indexes", ERROR_INVALID_INDEX) 449 | fromIndex=int(idx[0]) 450 | toIndex=int(idx[1]) 451 | if fromIndex == toIndex: 452 | error("ERROR: Source and destination cannot be the same", ERROR_INVALID_INDEX) 453 | rule=ufw.backend.get_rule_by_number(fromIndex).dup_rule() 454 | ufw.delete_rule(fromIndex, True) 455 | rule.position=toIndex 456 | insertRule(ufw, rule) 457 | 458 | def reset(ufw): 459 | loadDefaultSettings(ufw) 460 | clearRules(ufw) 461 | ufw.reset(True) 462 | if ufw.backend._is_enabled(): 463 | ufw.set_enabled(False) 464 | ufw.set_enabled(True) 465 | 466 | def clearRules(ufw): 467 | # removeDescriptions() 468 | count=ufw.backend.get_rules_count(False)+ufw.backend.get_rules_count(True) 469 | for num in range(0, count): 470 | try: 471 | ufw.delete_rule(1, True) 472 | except ufw.common.UFWError as e: 473 | pass 474 | 475 | def getModules(ufw, xmlStr): 476 | xmlStr.write("") 482 | 483 | def setModules(ufw, xml): 484 | elem = etree.XML(xml) 485 | if elem.tag != 'modules': 486 | error("ERROR: Invalid XML, expected \'modules' element", ERROR_INVALID_XML_NO_MODULES) 487 | modules=elem.get('enabled', '').lower() 488 | modules = '"' + modules + '"' 489 | ufw.backend.set_default(ufw.backend.files['defaults'], 'IPT_MODULES', modules) 490 | 491 | # def getProfiles(ufw, xmlStr): 492 | # xmlStr.write("") 502 | 503 | def error(str, rv): 504 | print >> sys.stderr, str 505 | #sys.exit(rv) 506 | 507 | def main(): 508 | try: 509 | # opts, args = getopt.getopt(sys.argv[1:], "hse:df:la:u:U:r:m:tiI:x", 510 | # ["help", "status", "setEnabled=", "defaults", "setDefaults=", "list", "add=", 511 | # "update=", "updateDescr=", "remove=", "move=", "reset", "modules", "setModules=", "clearRules"]) 512 | opts, args = getopt.getopt(sys.argv[1:], "hse:df:la:u:U:r:m:tiI:x", 513 | ["help", "status", "setEnabled=", "defaults", "setDefaults=", "list", "add=", 514 | "update=", "remove=", "move=", "reset", "modules", "setModules=", "clearRules"]) 515 | except getopt.GetoptError as err: 516 | # print help information and exit: 517 | print >> sys.stderr, str(err) # will print something like "option -a not recognized" 518 | usage() 519 | sys.exit(1) 520 | # loadDescriptions() 521 | returnXml = False 522 | xmlOut = io.StringIO() 523 | xmlOut.write("") 524 | for o, a in opts: 525 | if o in ("-h", "--help"): 526 | usage() 527 | sys.exit() 528 | elif o in ("-s", "--status"): 529 | getStatus(ufw, xmlOut) 530 | returnXml=True 531 | elif o in ("-e", "--setEnabled"): 532 | setEnabled(ufw, a) 533 | elif o in ("-d", "--defaults"): 534 | getDefaults(ufw, xmlOut) 535 | returnXml=True 536 | elif o in ("-f", "--setDefaults"): 537 | setDefaults(ufw, a) 538 | elif o in ("-l", "--list"): 539 | getRules(ufw, xmlOut) 540 | returnXml=True 541 | elif o in ("-a", "--add"): 542 | addRule(ufw, a) 543 | elif o in ("-u", "--update"): 544 | updateRule(ufw, a) 545 | # elif o in ("-U", "--updateDescr"): 546 | # updateRuleDescr(ufw, a) 547 | elif o in ("-r", "--remove"): 548 | removeRule(ufw, a) 549 | elif o in ("-m", "--move"): 550 | moveRule(ufw, a) 551 | elif o in ("-t", "--reset"): 552 | reset(ufw) 553 | elif o in ("-i", "--modules"): 554 | getModules(ufw, xmlOut) 555 | returnXml=True 556 | elif o in ("-I", "--setModules"): 557 | setModules(ufw, a) 558 | elif o in ("-x", "--clearRules"): 559 | clearRules(ufw) 560 | else: 561 | usage() 562 | # saveDescriptions() 563 | if returnXml: 564 | xmlOut.write("") 565 | print (xmlOut.getvalue()) 566 | 567 | def usage(): 568 | print ("Python helper for UFW KCM") 569 | print ("") 570 | print ("(C) Craig Drummond, 2011") 571 | print ("") 572 | print ("Usage:") 573 | print (" "+sys.argv[0]+" --status") 574 | print (" "+sys.argv[0]+" --setEnabled ") 575 | print (" "+sys.argv[0]+" --defaults") 576 | print (" "+sys.argv[0]+" --setDefaults ") 577 | print (" "+sys.argv[0]+" --list") 578 | print (" "+sys.argv[0]+" --add ") 579 | print (" "+sys.argv[0]+" --update ") 580 | # print (" "+sys.argv[0]+" --updateDescr ") 581 | print (" "+sys.argv[0]+" --remove ") 582 | print (" "+sys.argv[0]+" --remove ") 583 | print (" "+sys.argv[0]+" --move ") 584 | print (" "+sys.argv[0]+" --reset") 585 | print (" "+sys.argv[0]+" --modules") 586 | print (" "+sys.argv[0]+" --setModules ") 587 | print (" "+sys.argv[0]+" --clearRules") 588 | 589 | if __name__ == "__main__": 590 | main() 591 | -------------------------------------------------------------------------------- /plugins/ufw/helper/org.kde.ufw.service.cmake: -------------------------------------------------------------------------------- 1 | [D-BUS Service] 2 | Name=org.kde.ufw 3 | Exec=@LIBEXEC_INSTALL_DIR@/kcm_ufw_helper 4 | 5 | -------------------------------------------------------------------------------- /plugins/ufw/helper/org.nomad.ufw.actions: -------------------------------------------------------------------------------- 1 | [Domain] 2 | Name=Uncomplicated Firewall 3 | Name[cs]=Nekomplikovaný firewall 4 | Name[de]=Unkomplizierte Firewall 5 | Name[es]=Cortafuegos simple 6 | Name[fr]=Pare-feu simplifié 7 | Name[gl]=Devase sen complicacións 8 | Name[hu]=Egyszerű tűzfal 9 | Name[nl]=Eenvoudige firewall 10 | Name[pt]='Firewall' Simplificada 11 | Name[pt_BR]=Firewall descomplicado 12 | Name[sk]=Nekomplikovaný firewall 13 | Name[sv]=Okomplicerad brandvägg 14 | Name[tr]=Karmaşık Olmayan Güvenlik Duvarı 15 | Name[uk]=Нескладний брандмауер 16 | Name[x-test]=xxUncomplicated Firewallxx 17 | Icon=security-high 18 | [org.nomad.ufw.query] 19 | Name=Query Firewall 20 | Name[cs]=Dotázat se firewallu 21 | Name[de]=Firewall abfragen 22 | Name[es]=Consultar el cortafuegos 23 | Name[fr]=Interroger le pare-feu 24 | Name[gl]=Consultar a devasa 25 | Name[hu]=Tűzfal lekérdezése 26 | Name[nl]=Firewall afvragen 27 | Name[pt]=Consultar a 'Firewall' 28 | Name[pt_BR]=Pesquisa no firewall 29 | Name[sk]=Dotaz na firewall 30 | Name[sv]=Fråga brandvägg 31 | Name[tr]=Sorgu Güvenlik Duvarı 32 | Name[uk]=Надіслати запит до брандмауера 33 | Name[x-test]=xxQuery Firewallxx 34 | Description=Query firewall status 35 | Description[cs]=Dotázat se na stav firewallu 36 | Description[de]=Firewallstatus abfragen 37 | Description[es]=Consultar el estado del cortafuegos 38 | Description[fr]=Interroger le pare-feu sur son état 39 | Description[gl]=Estado da consulta á devasa 40 | Description[hu]=Tűzfalállapot lekérdezése 41 | Description[nl]=Status van firewall afvragen 42 | Description[pt]=Consultar o estado da 'firewall' 43 | Description[pt_BR]=Status da pesquisa no firewall 44 | Description[sk]=Dotaz na stav firewallu 45 | Description[sv]=Fråga om brandväggens status 46 | Description[tr]=Sorgu güvenlik duvarı durumu 47 | Description[uk]=Стан запиту до брандмауера 48 | Description[x-test]=xxQuery firewall statusxx 49 | Policy=yes 50 | Persistence=session 51 | [org.nomad.ufw.viewlog] 52 | Name=View Firewall Logs 53 | Name[cs]=Zobrazit záznamy firewallu 54 | Name[de]=Firewall-Protokolle anzeigen 55 | Name[es]=Ver los registros del cortafuegos 56 | Name[fr]=Afficher les messages du pare-feu 57 | Name[gl]=Ver os rexistros da devasa 58 | Name[hu]=Tűzfalnaplók megtekintése 59 | Name[nl]=Firewall-logs bekijken 60 | Name[pt]=Ver os Registos da 'Firewall' 61 | Name[pt_BR]=Exibir os registros do firewall 62 | Name[sk]=Zobraziť záznamy firewallu 63 | Name[sv]=Visa brandväggens loggar 64 | Name[tr]=Güvenlik Duvarı Günlüklerini Görüntüle 65 | Name[uk]=Переглянути журнал брандмауера 66 | Name[x-test]=xxView Firewall Logsxx 67 | Description=View firewall logs 68 | Description[cs]=Zobrazit záznamy firewallu 69 | Description[de]=Firewall-Protokolle anzeigen 70 | Description[es]=Ver los registros del cortafuegos 71 | Description[fr]=Afficher les messages du pare-feu 72 | Description[gl]=Visualiza o historial da devasa 73 | Description[hu]=Tűzfalnaplók megtekintése 74 | Description[nl]=Firewall-logs bekijken 75 | Description[pt]=Ver os registos da 'firewall' 76 | Description[pt_BR]=Exibe os registros do firewall 77 | Description[sk]=Zobraziť záznamy firewallu 78 | Description[sv]=Visa brandväggens loggar 79 | Description[tr]=Güvenlik duvarı günlüklerini görüntüle 80 | Description[uk]=Переглянути журнал роботи брандмауера 81 | Description[x-test]=xxView firewall logsxx 82 | Policy=yes 83 | Persistence=session 84 | [org.nomad.ufw.modify] 85 | Name=Modify Firewall 86 | Name[cs]=Upravit firewall 87 | Name[de]=Firewall bearbeiten 88 | Name[es]=Modificar el cortafuegos 89 | Name[fr]=Modifier le pare-feu 90 | Name[gl]=Modificar a devasa 91 | Name[hu]=Tűzfal módosítása 92 | Name[nl]=Firewall wijzigen 93 | Name[pt]=Modificar a 'Firewall' 94 | Name[pt_BR]=Modificar o firewall 95 | Name[sk]=Zmeniť firewall 96 | Name[sv]=Ändra brandväggen 97 | Name[tr]=Güvenlik Duvarını Değiştir 98 | Name[uk]=Змінити параметри брандмауера 99 | Name[x-test]=xxModify Firewallxx 100 | Description=Modify firewall settings 101 | Description[cs]=Upravit nastavení firewallu 102 | Description[de]=Firewall-Einstellungen bearbeiten 103 | Description[es]=Modificar las preferencias del cortafuegos 104 | Description[fr]=Modifier les paramètres du pare-feu 105 | Description[gl]=Cambia a configuración da devasa 106 | Description[hu]=Tűzfalbeállítások módosítása 107 | Description[nl]=Firewall-instellingen wijzigen 108 | Description[pt]=Modificar a configuração da 'firewall' 109 | Description[pt_BR]=Modificar as configurações do firewall 110 | Description[sk]=Zmeniť nastavenia firewallu 111 | Description[sv]=Ändra brandväggens inställningar 112 | Description[tr]=Güvenlik duvarı ayarlarını değiştir 113 | Description[uk]=Змінити параметри роботи брандмауера 114 | Description[x-test]=xxModify firewall settingsxx 115 | Policy=auth_admin 116 | Persistence=session 117 | -------------------------------------------------------------------------------- /plugins/ufw/helper/ufw_helper_config.h.cmake: -------------------------------------------------------------------------------- 1 | #ifndef UFW_HELPER_CONFIG_H 2 | #define UFW_HELPER_CONFIG_H 3 | 4 | #define UFW_PLUGIN_HELPER_PATH "${UFW_PLUGIN_HELPER_PATH}" 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /plugins/ufw/loglistmodel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Alexis Lopes Zubeta 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "loglistmodel.h" 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | LogListModel::LogListModel(QObject *parent) 28 | : QAbstractListModel(parent) 29 | { 30 | } 31 | 32 | int LogListModel::rowCount(const QModelIndex &parent) const 33 | { 34 | // For list models only the root node (an invalid parent) should return the list's size. For all 35 | // other (valid) parents, rowCount() should return 0 so that it does not become a tree model. 36 | if (parent.isValid()) 37 | return 0; 38 | 39 | return m_logsData.size(); 40 | } 41 | 42 | QVariant LogListModel::data(const QModelIndex &index, int role) const 43 | { 44 | if (!index.isValid()) 45 | return QVariant(); 46 | 47 | if (index.row() >= 0 && index.row() < m_logsData.size()) { 48 | QVariantList logData = m_logsData[index.row()].toList(); 49 | 50 | int valueIndex = role - (Qt::UserRole + 1); 51 | if (valueIndex >= logData.size()) 52 | return QString(); 53 | else 54 | return logData.value(valueIndex); 55 | } 56 | 57 | return QVariant(); 58 | } 59 | 60 | void LogListModel::addRawLogs(QStringList rawLogsList) 61 | { 62 | beginInsertRows(QModelIndex(), 0, rawLogsList.size() - 1); 63 | // UNSCAPED REGEX: (.*)\s(.*)\s(.*):\s\[(.*)\]\s\[(.*)\].*IN=([\w|\d]*).*SRC=([\w|\.|\d]*).*DST=([\w|\.|\d]*).*PROTO=([\w|\.|\d]*)\s(SPT=(\d*)\sDPT=(\d*))?.* 64 | static QRegularExpression regex("(.*)\\s(.*)\\s(.*):\\s\\[(.*)\\]\\s\\[(.*)\\].*IN=([\\w|\\d]*).*SRC=([\\w|\\.|\\d]*).*DST=([\\w|\\.|\\d]*).*PROTO=([\\w|\\.|\\d]*)\\s(SPT=(\\d*)\\sDPT=(\\d*))?.*"); 65 | for (QString log : rawLogsList) { 66 | 67 | auto match = regex.match(log); 68 | if (match.hasMatch()) { 69 | QDateTime date = QDateTime::fromString(match.captured(1), "MMM d HH:mm:ss"); 70 | QString host = match.captured(2); 71 | QString id = match.captured(4); 72 | QString action = match.captured(5); 73 | QString interface = match.captured(6); 74 | QString sourceAddress = match.captured(7); 75 | QString destinationAddress = match.captured(8); 76 | QString protocol = match.captured(9); 77 | QString sourcePort = match.captured(11); 78 | QString destinationPort = match.captured(12); 79 | 80 | // qDebug() << "host" << host; 81 | // qDebug() << "id" << id; 82 | // qDebug() << "action" << action; 83 | // qDebug() << "interface" << interface; 84 | // qDebug() << "sourceAddress" << sourceAddress; 85 | // qDebug() << "destinationAddress" << destinationAddress; 86 | // qDebug() << "protocol" << protocol; 87 | // qDebug() << "sourcePort" << sourcePort; 88 | // qDebug() << "destinationPort" << destinationPort; 89 | QVariantList logDetails; 90 | 91 | logDetails << sourceAddress << sourcePort; 92 | logDetails << destinationAddress << destinationPort; 93 | logDetails << protocol << interface; 94 | logDetails << action << date.toString("HH:mm:ss") << date.toString("MMM dd"); 95 | 96 | m_logsData.push_front((QVariant) logDetails); 97 | } 98 | } 99 | endInsertRows(); 100 | } 101 | 102 | QHash LogListModel::roleNames() const 103 | { 104 | return { 105 | {SourceAddressRole, "sourceAddress"}, 106 | {SourcePortRole, "sourcePort"}, 107 | {DestinationAddressRole, "destinationAddress"}, 108 | {DestinationPortRole, "destinationPort"}, 109 | {ProtocolRole, "protocol"}, 110 | {InterfaceRole, "interface"}, 111 | {ActionRole, "action"}, 112 | {TimeRole, "time"}, 113 | {DateRole, "date"}, 114 | }; 115 | } 116 | -------------------------------------------------------------------------------- /plugins/ufw/loglistmodel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Alexis Lopes Zubeta 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #ifndef LOGLISTMODEL_H 22 | #define LOGLISTMODEL_H 23 | 24 | #include 25 | #include 26 | 27 | class LogListModel : public QAbstractListModel 28 | { 29 | Q_OBJECT 30 | 31 | public: 32 | explicit LogListModel(QObject *parent = nullptr); 33 | 34 | enum LogItemModelRoles 35 | { 36 | SourceAddressRole = Qt::UserRole + 1, 37 | SourcePortRole, 38 | DestinationAddressRole, 39 | DestinationPortRole, 40 | ProtocolRole, 41 | InterfaceRole, 42 | ActionRole, 43 | TimeRole, 44 | DateRole, 45 | }; 46 | 47 | 48 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; 49 | 50 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 51 | 52 | void addRawLogs(QStringList rawLogsList); 53 | protected: 54 | QHash roleNames() const override; 55 | 56 | private: 57 | QVariantList m_logsData; 58 | }; 59 | 60 | #endif // LOGLISTMODEL_H 61 | -------------------------------------------------------------------------------- /plugins/ufw/profile.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * UFW KControl Module 3 | * 4 | * Copyright 2011 Craig Drummond 5 | * 6 | * ---- 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; see the file COPYING. If not, write to 20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 | * Boston, MA 02110-1301, USA. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "profile.h" 33 | 34 | namespace UFW 35 | { 36 | 37 | Profile::Profile(const QByteArray &xml, bool isSys) 38 | : fields(0) 39 | , enabled(false) 40 | , ipv6Enabled(false) 41 | , logLevel(Types::LOG_OFF) 42 | , defaultIncomingPolicy(Types::POLICY_ALLOW) 43 | , defaultOutgoingPolicy(Types::POLICY_ALLOW) 44 | , isSystem(isSys) 45 | { 46 | QDomDocument doc; 47 | doc.setContent(xml); 48 | load(doc); 49 | } 50 | 51 | Profile::Profile(QFile &file, bool isSys) 52 | : fields(0) 53 | , enabled(false) 54 | , ipv6Enabled(false) 55 | , logLevel(Types::LOG_OFF) 56 | , defaultIncomingPolicy(Types::POLICY_ALLOW) 57 | , defaultOutgoingPolicy(Types::POLICY_ALLOW) 58 | , fileName(file.fileName()) 59 | , isSystem(isSys) 60 | { 61 | QDomDocument doc; 62 | 63 | if(file.open(QIODevice::ReadOnly)) 64 | { 65 | doc.setContent(&file); 66 | load(doc); 67 | } 68 | } 69 | 70 | QString Profile::toXml() const 71 | { 72 | QString str; 73 | QTextStream stream(&str); 74 | QList::ConstIterator it(rules.constBegin()), 75 | end(rules.constEnd()); 76 | 77 | stream << "" << endl 78 | << ' ' << defaultsXml() << endl 79 | << " " << endl; 80 | for(; it!=end; ++it) 81 | stream << " " << (*it).toXml(); 82 | stream << " " << endl 83 | << ' ' << modulesXml() << endl 84 | << "" << endl; 85 | 86 | return str; 87 | } 88 | 89 | QString Profile::defaultsXml() const 90 | { 91 | return QString(""); 95 | } 96 | 97 | QString Profile::modulesXml() const 98 | { 99 | return QString(""); 100 | } 101 | 102 | void Profile::load(const QDomDocument &doc) 103 | { 104 | QDomNode ufw=doc.namedItem("ufw"); 105 | 106 | if(!ufw.isNull()) 107 | { 108 | QDomElement elem=ufw.toElement(); 109 | bool isFull=elem.attribute("full")=="true"; 110 | 111 | QDomNode status=ufw.namedItem("status"); 112 | if(!status.isNull()) 113 | { 114 | QDomElement elem=status.toElement(); 115 | enabled=elem.attribute("enabled")=="true"; 116 | fields|=FIELD_STATUS; 117 | } 118 | 119 | QDomNode rulesNode=ufw.namedItem("rules"), 120 | defaultsNode=ufw.namedItem("defaults"), 121 | modulesNode=ufw.namedItem("modules"); 122 | 123 | if(!rulesNode.isNull()) 124 | { 125 | QDomNodeList nodes=rulesNode.childNodes(); 126 | 127 | fields|=FIELD_RULES; 128 | if(nodes.count()>0) 129 | { 130 | for(int i=0; i 8 | * 9 | * ---- 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program; see the file COPYING. If not, write to 23 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301, USA. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include "rule.h" 31 | #include "types.h" 32 | 33 | class QFile; 34 | class QDomDocument; 35 | 36 | namespace UFW 37 | { 38 | 39 | class Profile 40 | { 41 | public: 42 | 43 | enum Fields 44 | { 45 | FIELD_RULES = 0x01, 46 | FIELD_DEFAULTS = 0x02, 47 | FIELD_MODULES = 0x04, 48 | FIELD_STATUS = 0x08 49 | }; 50 | 51 | Profile() 52 | : fields(0), enabled(false), ipv6Enabled(false) 53 | { 54 | } 55 | Profile(const QByteArray &xml, bool isSys=false); 56 | Profile(QFile &file, bool isSys=false); 57 | Profile(bool ipv6, Types::LogLevel ll, Types::Policy dip, Types::Policy dop, const QList &r, const QSet &m) 58 | : fields(0xFF), enabled(true), ipv6Enabled(ipv6), logLevel(ll), defaultIncomingPolicy(dip), defaultOutgoingPolicy(dop) 59 | , rules(r), modules(m), isSystem(false) 60 | { 61 | } 62 | 63 | bool operator==(const Profile &o) const 64 | { 65 | return ipv6Enabled==o.ipv6Enabled && 66 | logLevel==o.logLevel && 67 | defaultIncomingPolicy==o.defaultIncomingPolicy && 68 | defaultOutgoingPolicy==o.defaultOutgoingPolicy && 69 | rules==o.rules && 70 | modules==o.modules; 71 | } 72 | 73 | QString toXml() const; 74 | QString defaultsXml() const; 75 | QString modulesXml() const; 76 | 77 | bool hasRules() const { return fields&FIELD_RULES; } 78 | bool hasDefaults() const { return fields&FIELD_DEFAULTS; } 79 | bool hasModules() const { return fields&FIELD_MODULES; } 80 | bool hasStatus() const { return fields&FIELD_STATUS; } 81 | 82 | int getFields() const { return fields; } 83 | bool getEnabled() const { return enabled; } 84 | bool getIpv6Enabled() const { return ipv6Enabled; } 85 | Types::LogLevel getLogLevel() const { return logLevel; } 86 | Types::Policy getDefaultIncomingPolicy() const { return defaultIncomingPolicy; } 87 | Types::Policy getDefaultOutgoingPolicy() const { return defaultOutgoingPolicy; } 88 | const QList & getRules() const { return rules; } 89 | const QSet & getModules() const { return modules; } 90 | const QString & getFileName() const { return fileName; } 91 | bool getIsSystem() const { return isSystem; } 92 | 93 | private: 94 | 95 | void load(const QDomDocument &doc); 96 | 97 | private: 98 | 99 | int fields; 100 | bool enabled, 101 | ipv6Enabled; 102 | Types::LogLevel logLevel; 103 | Types::Policy defaultIncomingPolicy, 104 | defaultOutgoingPolicy; 105 | QList rules; 106 | QSet modules; 107 | QString fileName; 108 | bool isSystem; 109 | 110 | }; 111 | 112 | } 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /plugins/ufw/qmldir: -------------------------------------------------------------------------------- 1 | module org.nomad.ufw 2 | plugin nomad_ufw_plugin 3 | -------------------------------------------------------------------------------- /plugins/ufw/rule.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * UFW KControl Module 3 | * 4 | * Copyright 2011 Craig Drummond 5 | * 6 | * ---- 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; see the file COPYING. If not, write to 20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 | * Boston, MA 02110-1301, USA. 22 | */ 23 | 24 | #include "rule.h" 25 | #include "appprofiles.h" 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | namespace UFW 35 | { 36 | 37 | // Keep in sync with kcm_ufw_helper.py 38 | static const char * ANY_ADDR = "0.0.0.0/0"; 39 | static const char * ANY_ADDR_V6 = "::/0"; 40 | static const char * ANY_PORT = "any"; 41 | static const char * ANY_PROTOCOL = "any"; 42 | 43 | // Shorten an IPv6 address (if applicable) 44 | static QString shortenAddress(const QString &addr) 45 | { 46 | if(!addr.isEmpty() && addr.contains(":")) 47 | { 48 | QByteArray bytes(addr.toLatin1()); 49 | unsigned char num[16]; 50 | 51 | if(inet_pton(AF_INET6, bytes.constData(), num)>0) 52 | { 53 | char conv[41]; 54 | if(NULL!=inet_ntop(AF_INET6, num, conv, 41)) 55 | return QLatin1String(conv); 56 | } 57 | } 58 | return addr; 59 | } 60 | 61 | static QString addIface(const QString &orig, const QString &iface) 62 | { 63 | return iface.isEmpty() ? orig : i18nc("address on interface", "%1 on %2", orig, iface); 64 | } 65 | 66 | static QString getServiceName(short port) 67 | { 68 | static QMap serviceMap; 69 | 70 | if(serviceMap.contains(port)) 71 | return serviceMap[port]; 72 | 73 | struct servent *ent=getservbyport(htons(port), 0L); 74 | 75 | if(ent && ent->s_name) 76 | { 77 | serviceMap[port]=ent->s_name; 78 | return serviceMap[port]; 79 | } 80 | 81 | return QString(); 82 | } 83 | 84 | static QString formatPort(const QString &port, Types::Protocol prot) 85 | { 86 | return port.isEmpty() ? Rule::protocolSuffix(prot, QString()) 87 | : port+Rule::protocolSuffix(prot); 88 | } 89 | 90 | // Try to convert 'port' into a port number, not a service name... 91 | static QString getPortNumber(const QString &port) 92 | { 93 | if(-1==port.indexOf(':')) 94 | { 95 | bool ok; 96 | int num=port.toInt(&ok); 97 | 98 | if(!ok) // 'port' is not a number... 99 | { 100 | num=Rule::getServicePort(port); 101 | if(0!=num) 102 | return QString().setNum(num); 103 | } 104 | } 105 | 106 | return port; 107 | } 108 | 109 | static QString modifyAddress(const QString &addr, const QString &port) 110 | { 111 | if(addr.isEmpty() || ANY_ADDR==addr || ANY_ADDR_V6==addr) 112 | { 113 | if(port.isEmpty()) 114 | return i18n("Anywhere"); 115 | else 116 | return QString(); 117 | } 118 | 119 | return shortenAddress(addr); 120 | } 121 | 122 | static QString modifyPort(const QString &port, Types::Protocol prot, bool matchPortNoProto=false) 123 | { 124 | if(port.isEmpty()) 125 | return port; 126 | // Does it match a pre-configured application? 127 | Types::PredefinedPort pp=Types::toPredefinedPort(port+Rule::protocolSuffix(prot)); 128 | 129 | // When matchin glog lines, the protocol is *always* specified - but dont alwys want this when 130 | // matching names... 131 | if(matchPortNoProto && Types::PP_COUNT==pp) 132 | pp=Types::toPredefinedPort(port); 133 | 134 | if(Types::PP_COUNT!=pp) 135 | return i18nc("serice/application name (port numbers)", "%1 (%2)", Types::toString(pp, true), port+Rule::protocolSuffix(prot)); 136 | 137 | // Is it a service known to /etc/services ??? 138 | bool ok(false); 139 | QString service; 140 | short portNum=port.toShort(&ok); 141 | 142 | if(ok) 143 | service=getServiceName(portNum); 144 | 145 | if(!service.isEmpty()) 146 | return i18nc("serice/application name (port numbers)", "%1 (%2)", service, formatPort(port, prot)); 147 | 148 | // Just return port/sericename and protocol 149 | return formatPort(port, prot); 150 | } 151 | 152 | static QString modifyApp(const QString &app, const QString &port, Types::Protocol prot) 153 | { 154 | if(app.isEmpty()) 155 | return port; 156 | 157 | AppProfiles::Entry profile(AppProfiles::get(app)); 158 | 159 | return i18nc("serice/application name (port numbers)", "%1 (%2)", app, profile.name.isEmpty() ? formatPort(port, prot) : profile.ports); 160 | } 161 | 162 | int Rule::getServicePort(const QString &name) 163 | { 164 | static QMap serviceMap; 165 | 166 | if(serviceMap.contains(name)) 167 | return serviceMap[name]; 168 | 169 | QByteArray l1=name.toLatin1(); 170 | struct servent *ent=getservbyname(l1.constData(), 0L); 171 | 172 | if(ent && ent->s_name) 173 | { 174 | serviceMap[name]=ntohs(ent->s_port); 175 | return serviceMap[name]; 176 | } 177 | 178 | return 0; 179 | } 180 | 181 | QString Rule::protocolSuffix(Types::Protocol prot, const QString &sep) 182 | { 183 | return Types::PROTO_BOTH==prot ? "" : (sep+Types::toString(prot)); 184 | } 185 | 186 | QString Rule::modify(const QString &address, const QString &port, const QString &application, const QString iface, 187 | const Types::Protocol &protocol, bool matchPortNoProto) 188 | { 189 | if((port==ANY_PORT || port.isEmpty()) && (address.isEmpty() || ANY_ADDR==address || ANY_ADDR_V6==address)) 190 | return addIface(i18n("Anywhere"), iface); 191 | 192 | bool isAnyAddress=address.isEmpty() || ANY_ADDR==address || ANY_ADDR_V6==address, 193 | isAnyPort=port.isEmpty() || ANY_PORT==port; 194 | QString bPort=application.isEmpty() ? modifyPort(port, protocol, matchPortNoProto) : modifyApp(application, port, protocol), 195 | bAddr=modifyAddress(address, port); 196 | 197 | return addIface(isAnyAddress 198 | ? isAnyPort 199 | ? i18n("Anywhere") 200 | : bPort 201 | : bAddr.isEmpty() 202 | ? bPort 203 | : bAddr+QChar(' ')+bPort, 204 | iface); 205 | } 206 | 207 | Rule::Rule() 208 | : position(0) 209 | , action(Types::POLICY_REJECT) 210 | , incoming(true) 211 | , v6(false) 212 | , protocol(Types::PROTO_BOTH) 213 | , logtype(Types::LOGGING_OFF) 214 | { 215 | } 216 | 217 | Rule::Rule(QDomElement &elem) 218 | { 219 | QString val=elem.attribute("position"); 220 | 221 | position=val.toUInt(); 222 | val=elem.attribute("action"); 223 | action=Types::POLICY_ALLOW; 224 | if(!val.isEmpty()) 225 | for(int i=Types::POLICY_ALLOW; i 8 | * 9 | * ---- 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program; see the file COPYING. If not, write to 23 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301, USA. 25 | */ 26 | 27 | #include "types.h" 28 | #include 29 | #include 30 | 31 | class QDomElement; 32 | 33 | namespace UFW 34 | { 35 | 36 | class Rule 37 | { 38 | public: 39 | 40 | static int getServicePort(const QString &name); 41 | static QString protocolSuffix(Types::Protocol prot, const QString &sep=QString("/")); 42 | static QString modify(const QString &address, const QString &port, const QString &application, 43 | const QString iface, const Types::Protocol &protocol, bool matchPortNoProto=false); 44 | 45 | Rule(); 46 | Rule(QDomElement &elem); 47 | Rule(Types::Policy pol, bool in, Types::Logging log, Types::Protocol prot, 48 | // const QString &descr=QString(), const QString &hsh=QString(), 49 | const QString &srcHost=QString(), const QString &srcPort=QString(), 50 | const QString &destHost=QString(), const QString &destPort=QString(), 51 | const QString &ifaceIn=QString(), const QString &ifaceOut=QString(), 52 | const QString &srcApp=QString(), const QString &destApp=QString(), 53 | unsigned int i=0) 54 | : position(i), action(pol), incoming(in), v6(false), protocol(prot), logtype(log), 55 | destApplication(destApp), sourceApplication(srcApp), 56 | destAddress(destHost), sourceAddress(srcHost), destPort(destPort), sourcePort(srcPort), 57 | interfaceIn(ifaceIn), interfaceOut(ifaceOut) // , description(descr), hash(hsh) 58 | { } 59 | 60 | 61 | QString toStr() const; 62 | QString fromStr() const; 63 | QString actionStr() const; 64 | QString protocolStr() const; 65 | QString ipV6Str() const; 66 | QString loggingStr() const; 67 | QString toXml() const; 68 | 69 | int getPosition() const { return position; } 70 | Types::Policy getAction() const { return action; } 71 | bool getIncoming() const { return incoming; } 72 | bool getV6() const { return v6; } 73 | const QString & getDestApplication() const { return destApplication; } 74 | const QString & getSourceApplication() const { return sourceApplication; } 75 | const QString & getDestAddress() const { return destAddress; } 76 | const QString & getSourceAddress() const { return sourceAddress; } 77 | const QString & getDestPort() const { return destPort; } 78 | const QString & getSourcePort() const { return sourcePort; } 79 | const QString & getInterfaceIn() const { return interfaceIn; } 80 | const QString & getInterfaceOut() const { return interfaceOut; } 81 | Types::Protocol getProtocol() const { return protocol; } 82 | Types::Logging getLogging() const { return logtype; } 83 | // const QString & getDescription() const { return description; } 84 | // const QString & getHash() const { return hash; } 85 | 86 | void setPosition(unsigned int v) { position=v; } 87 | void setAction(Types::Policy v) { action=v; } 88 | void setIncoming(bool v) { incoming=v; } 89 | void setV6(bool v) { v6=v; } 90 | void setDestApplication(const QString &v) { destApplication=v; } 91 | void setSourceApplication(const QString &v) { sourceApplication=v; } 92 | void setDestAddress(const QString &v) { destAddress=v; } 93 | void setSourceAddress(const QString &v) { sourceAddress=v; } 94 | void setDestPort(const QString &v) { destPort=v; } 95 | void setSourcePort(const QString &v) { sourcePort=v; } 96 | void setInterfaceIn(const QString &v) { interfaceIn=v; } 97 | void setInterfaceOut(const QString &v) { interfaceOut=v; } 98 | void setProtocol(Types::Protocol v) { protocol=v; } 99 | void setLogging(Types::Logging v) { logtype=v; } 100 | // void setDescription(const QString &v) { description=v; } 101 | // void setHash(const QString &v) { hash=v; } 102 | 103 | // 'different' is used in the EditRule dialog to know whether the rule has actually changed... 104 | bool different(const Rule &o) const 105 | { 106 | return logtype!=o.logtype /*|| description!=o.description*/ || !(*this==o); 107 | } 108 | 109 | // bool onlyDescrChanged(const Rule &o) const 110 | // { 111 | // return (*this==o) && logtype==o.logtype && description!=o.description; 112 | // } 113 | 114 | bool operator==(const Rule &o) const 115 | { 116 | return action==o.action && 117 | incoming==o.incoming && 118 | v6==o.v6 && 119 | protocol==o.protocol && 120 | //logtype==o.logtype && 121 | destApplication==o.destApplication && 122 | sourceApplication==o.sourceApplication && 123 | destAddress==o.destAddress && 124 | sourceAddress==o.sourceAddress && 125 | (destApplication.isEmpty() && o.destApplication.isEmpty() ? destPort==o.destPort : true) && 126 | (sourceApplication.isEmpty() && o.sourceApplication.isEmpty() ? sourcePort==o.sourcePort : true) && 127 | interfaceIn==o.interfaceIn && 128 | interfaceOut==o.interfaceOut; 129 | } 130 | 131 | private: 132 | 133 | int position; 134 | Types::Policy action; 135 | bool incoming, 136 | v6; 137 | Types::Protocol protocol; 138 | Types::Logging logtype; 139 | QString destApplication, 140 | sourceApplication, 141 | destAddress, 142 | sourceAddress, 143 | destPort, 144 | sourcePort, 145 | interfaceIn, 146 | interfaceOut; 147 | // description, 148 | // hash; 149 | }; 150 | 151 | } 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /plugins/ufw/rulelistmodel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Alexis Lopes Zubeta 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "rulelistmodel.h" 22 | 23 | #include 24 | 25 | RuleListModel::RuleListModel(QObject *parent) 26 | : QAbstractListModel(parent) 27 | { 28 | } 29 | 30 | void RuleListModel::add(int index) 31 | { 32 | beginInsertRows(QModelIndex(), index, index); 33 | // TODO 34 | qDebug() << "Add rule not implemented yet"; 35 | endInsertRows(); 36 | } 37 | 38 | void RuleListModel::remove(int index) 39 | { 40 | beginRemoveRows(QModelIndex(), index, index); 41 | // TODO 42 | qDebug() << "Remove rule not implemented yet"; 43 | endRemoveRows(); 44 | } 45 | 46 | void RuleListModel::move(int from, int to) 47 | { 48 | if(to < 0 && to >= m_rules.count()) 49 | return; 50 | 51 | int newPos = to > from ? to + 1 : to; 52 | bool validMove = beginMoveRows(QModelIndex(), from, from, QModelIndex(), newPos); 53 | if (validMove) 54 | { 55 | m_rules.move(from, to); 56 | endMoveRows(); 57 | } 58 | } 59 | 60 | void RuleListModel::change(int index) 61 | { 62 | // TODO 63 | qDebug() << "Change rule not implemented yet"; 64 | dataChanged(QModelIndex(), createIndex(index, 0)); 65 | } 66 | 67 | int RuleListModel::rowCount(const QModelIndex &parent) const 68 | { 69 | Q_UNUSED(parent); 70 | return m_rules.count(); 71 | } 72 | 73 | QVariant RuleListModel::data(const QModelIndex &index, int role) const 74 | { 75 | if (index.row() < 0 || index.row() >= m_rules.count()) { 76 | return {}; 77 | } 78 | 79 | const UFW::Rule rule = m_rules.at(index.row()); 80 | 81 | switch(role) { 82 | case ActionRole: return rule.actionStr(); 83 | case FromRole: return rule.fromStr(); 84 | case ToRole: return rule.toStr(); 85 | case Ipv6Role: return rule.getV6(); 86 | case LoggingRole: return rule.loggingStr(); 87 | } 88 | return {}; 89 | } 90 | 91 | void RuleListModel::setProfile(UFW::Profile profile) 92 | { 93 | beginResetModel(); 94 | m_profile = profile; 95 | m_rules = m_profile.getRules(); 96 | 97 | endResetModel(); 98 | } 99 | 100 | QHash RuleListModel::roleNames() const 101 | { 102 | return { 103 | {ActionRole, "action"}, 104 | {FromRole, "from"}, 105 | {ToRole, "to"}, 106 | {Ipv6Role, "ipv6"}, 107 | {LoggingRole, "logging"}, 108 | }; 109 | } 110 | -------------------------------------------------------------------------------- /plugins/ufw/rulelistmodel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Alexis Lopes Zubeta 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #ifndef PROFILEITEMMODEL_H 22 | #define PROFILEITEMMODEL_H 23 | 24 | #include 25 | 26 | #include "rulewrapper.h" 27 | #include "profile.h" 28 | 29 | class RuleListModel : public QAbstractListModel 30 | 31 | { 32 | Q_OBJECT 33 | 34 | public: 35 | enum ProfileItemModelRoles 36 | { 37 | ActionRole = Qt::UserRole + 1, 38 | FromRole, 39 | ToRole, 40 | Ipv6Role, 41 | LoggingRole 42 | }; 43 | 44 | explicit RuleListModel(QObject *parent = nullptr); 45 | 46 | Q_INVOKABLE void add(int index); 47 | Q_INVOKABLE void remove(int index); 48 | Q_INVOKABLE void move(int from, int to); 49 | Q_INVOKABLE void change(int index); 50 | 51 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; 52 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 53 | 54 | void setProfile(UFW::Profile profile); 55 | protected: 56 | QHash roleNames() const override; 57 | 58 | private: 59 | UFW::Profile m_profile; 60 | QList m_rules; 61 | }; 62 | 63 | #endif // PROFILEITEMMODEL_H 64 | -------------------------------------------------------------------------------- /plugins/ufw/rulewrapper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Alexis Lopes Zubeta 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "rulewrapper.h" 22 | 23 | #include "types.h" 24 | #include "ufwclient.h" 25 | 26 | #include 27 | 28 | RuleWrapper::RuleWrapper(QObject *parent) : QObject(parent), m_interface(0) 29 | { 30 | } 31 | 32 | RuleWrapper::RuleWrapper(UFW::Rule rule, QObject *parent) : QObject(parent), m_rule(rule) 33 | { 34 | 35 | QStringList interfaces = UfwClient::getKnownInterfaces(); 36 | QString interface_name = m_rule.getInterfaceIn(); 37 | 38 | int iface_index = interfaces.indexOf(interface_name); 39 | m_interface = iface_index == -1 ? 0 : iface_index; 40 | } 41 | 42 | QString RuleWrapper::policy() const 43 | { 44 | auto policy = m_rule.getAction(); 45 | return UFW::Types::toString(policy); 46 | } 47 | 48 | bool RuleWrapper::incoming() const 49 | { 50 | return m_rule.getIncoming(); 51 | } 52 | 53 | QString RuleWrapper::sourceAddress() const 54 | { 55 | return m_rule.getSourceAddress(); 56 | } 57 | 58 | QString RuleWrapper::sourcePort() const 59 | { 60 | return m_rule.getSourcePort(); 61 | } 62 | 63 | QString RuleWrapper::destinationAddress() const 64 | { 65 | return m_rule.getDestAddress(); 66 | } 67 | 68 | QString RuleWrapper::destinationPort() const 69 | { 70 | return m_rule.getDestPort(); 71 | } 72 | 73 | int RuleWrapper::protocol() const 74 | { 75 | auto protocol = m_rule.getProtocol(); 76 | return protocol; 77 | } 78 | 79 | int RuleWrapper::interface() const 80 | { 81 | return m_interface; 82 | } 83 | 84 | QString RuleWrapper::logging() const 85 | { 86 | auto logging = m_rule.getLogging(); 87 | return UFW::Types::toString(logging); 88 | } 89 | 90 | UFW::Rule RuleWrapper::getRule() 91 | { 92 | return m_rule; 93 | } 94 | 95 | int RuleWrapper::position() const 96 | { 97 | return m_rule.getPosition(); 98 | } 99 | 100 | void RuleWrapper::setPolicy(QString policy) 101 | { 102 | auto policy_t = UFW::Types::toPolicy(policy); 103 | 104 | if (policy_t == m_rule.getAction()) 105 | return; 106 | 107 | m_rule.setAction(policy_t); 108 | emit policyChanged(policy); 109 | } 110 | 111 | void RuleWrapper::setIncoming(bool incoming) 112 | { 113 | if (m_rule.getIncoming() == incoming) 114 | return; 115 | 116 | m_rule.setIncoming(incoming); 117 | emit incomingChanged(incoming); 118 | } 119 | 120 | void RuleWrapper::setSourceAddress(QString sourceAddress) 121 | { 122 | if (m_rule.getSourceAddress().compare(sourceAddress) == 0) 123 | return; 124 | 125 | m_rule.setSourceAddress(sourceAddress); 126 | emit sourceAddressChanged(sourceAddress); 127 | } 128 | 129 | void RuleWrapper::setSourcePort(QString sourcePort) 130 | { 131 | if (m_rule.getSourcePort().compare(sourcePort) == 0) 132 | return; 133 | 134 | m_rule.setSourcePort(sourcePort); 135 | emit sourcePortChanged(sourcePort); 136 | } 137 | 138 | void RuleWrapper::setDestinationAddress(QString destinationAddress) 139 | { 140 | if (m_rule.getDestAddress().compare(destinationAddress) == 0) 141 | return; 142 | 143 | m_rule.setDestAddress(destinationAddress); 144 | emit destinationAddressChanged(destinationAddress); 145 | } 146 | 147 | void RuleWrapper::setDestinationPort(QString destinationPort) 148 | { 149 | if (m_rule.getDestPort().compare(destinationPort) == 0) 150 | return; 151 | 152 | m_rule.setDestPort(destinationPort); 153 | emit destinationPortChanged(destinationPort); 154 | } 155 | 156 | void RuleWrapper::setProtocol(int protocol) 157 | { 158 | if (m_rule.getProtocol() == protocol) 159 | return; 160 | 161 | m_rule.setProtocol((UFW::Types::Protocol) protocol); 162 | emit protocolChanged(protocol); 163 | } 164 | 165 | void RuleWrapper::setInterface(int interface) 166 | { 167 | if (m_interface == interface) 168 | return; 169 | 170 | if (interface == 0) 171 | m_rule.setInterfaceIn(""); 172 | else { 173 | QStringList interfaces = UfwClient::getKnownInterfaces(); 174 | m_rule.setInterfaceIn(interfaces.at(interface)); 175 | } 176 | 177 | m_interface = interface; 178 | qDebug() << "new iface" << m_rule.getInterfaceIn(); 179 | emit interfaceChanged(interface); 180 | } 181 | 182 | void RuleWrapper::setLogging(QString logging) 183 | { 184 | auto logging_t = UFW::Types::toLogging(logging); 185 | if (m_rule.getLogging() == logging_t) 186 | return; 187 | 188 | m_rule.setLogging(logging_t); 189 | emit loggingChanged(logging); 190 | } 191 | 192 | void RuleWrapper::setPosition(int position) 193 | { 194 | if (m_rule.getPosition() == position) 195 | return; 196 | 197 | m_rule.setPosition(position); 198 | emit positionChanged(position); 199 | } 200 | 201 | 202 | -------------------------------------------------------------------------------- /plugins/ufw/rulewrapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Alexis Lopes Zubeta 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #ifndef RULEWRAPPER_H 22 | #define RULEWRAPPER_H 23 | 24 | #include 25 | 26 | #include "rule.h" 27 | #include "types.h" 28 | 29 | class RuleWrapper : public QObject 30 | { 31 | Q_OBJECT 32 | Q_PROPERTY(QString policy READ policy WRITE setPolicy NOTIFY policyChanged) 33 | Q_PROPERTY(bool incoming READ incoming WRITE setIncoming NOTIFY incomingChanged) 34 | Q_PROPERTY(QString sourceAddress READ sourceAddress WRITE setSourceAddress NOTIFY sourceAddressChanged) 35 | Q_PROPERTY(QString sourcePort READ sourcePort WRITE setSourcePort NOTIFY sourcePortChanged) 36 | Q_PROPERTY(QString destinationAddress READ destinationAddress WRITE setDestinationAddress NOTIFY destinationAddressChanged) 37 | Q_PROPERTY(QString destinationPort READ destinationPort WRITE setDestinationPort NOTIFY destinationPortChanged) 38 | Q_PROPERTY(int protocol READ protocol WRITE setProtocol NOTIFY protocolChanged) 39 | Q_PROPERTY(int interface READ interface WRITE setInterface NOTIFY interfaceChanged) 40 | Q_PROPERTY(QString logging READ logging WRITE setLogging NOTIFY loggingChanged) 41 | Q_PROPERTY(int position READ position WRITE setPosition NOTIFY positionChanged) 42 | public: 43 | explicit RuleWrapper(QObject *parent = nullptr); 44 | explicit RuleWrapper(UFW::Rule rule, QObject *parent = nullptr); 45 | 46 | QString policy() const; 47 | bool incoming() const; 48 | QString sourceAddress() const; 49 | QString sourcePort() const; 50 | QString destinationAddress() const; 51 | QString destinationPort() const; 52 | int protocol() const; 53 | int interface() const; 54 | QString logging() const; 55 | 56 | UFW::Rule getRule(); 57 | int position() const; 58 | 59 | signals: 60 | void policyChanged(QString policy); 61 | void directionChanged(QString direction); 62 | void sourceAddressChanged(QString sourceAddress); 63 | void sourcePortChanged(QString sourcePort); 64 | void destinationAddressChanged(QString destinationAddress); 65 | void destinationPortChanged(QString destinationPort); 66 | void protocolChanged(int protocol); 67 | void interfaceChanged(int interface); 68 | void loggingChanged(QString logging); 69 | void incomingChanged(bool incoming); 70 | 71 | void positionChanged(int position); 72 | 73 | public slots: 74 | void setPolicy(QString policy); 75 | void setIncoming(bool incoming); 76 | void setSourceAddress(QString sourceAddress); 77 | void setSourcePort(QString sourcePort); 78 | void setDestinationAddress(QString destinationAddress); 79 | void setDestinationPort(QString destinationPort); 80 | void setProtocol(int protocol); 81 | void setInterface(int interface); 82 | void setLogging(QString logging); 83 | 84 | void setPosition(int position); 85 | 86 | private: 87 | UFW::Rule m_rule; 88 | int m_interface; 89 | }; 90 | 91 | #endif // RULEWRAPPER_H 92 | -------------------------------------------------------------------------------- /plugins/ufw/types.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * UFW KControl Module 3 | * 4 | * Copyright 2011 Craig Drummond 5 | * 6 | * ---- 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; see the file COPYING. If not, write to 20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 | * Boston, MA 02110-1301, USA. 22 | */ 23 | 24 | #include "types.h" 25 | #include 26 | #include 27 | 28 | namespace UFW 29 | { 30 | 31 | namespace Types 32 | { 33 | 34 | QString toString(LogLevel level, bool ui) 35 | { 36 | switch(level) 37 | { 38 | case LOG_OFF: return ui ? i18n("Off") : "off"; 39 | default: 40 | case LOG_LOW: return ui ? i18n("Low") : "low"; 41 | case LOG_MEDIUM: return ui ? i18n("Medium") : "medium"; 42 | case LOG_HIGH: return ui ? i18n("High") : "high"; 43 | case LOG_FULL: return ui ? i18n("Full") : "full"; 44 | } 45 | } 46 | 47 | LogLevel toLogLevel(const QString &str) 48 | { 49 | for(int i=0; i(i); 125 | const auto typesAtIndex = Types::toString(enumPort).split(" "); 126 | 127 | for (const auto &port : typesAtIndex) { 128 | if (port == str) { 129 | return enumPort; 130 | } 131 | } 132 | } 133 | 134 | return PP_COUNT; 135 | } 136 | 137 | QString toString(Protocol proto, bool ui) 138 | { 139 | switch(proto) 140 | { 141 | case PROTO_TCP: return ui ? i18n("TCP") : "tcp"; 142 | case PROTO_UDP: return ui ? i18n("UDP") : "udp"; 143 | case PROTO_BOTH: return ui ? i18n("Any protocol") : QString(); 144 | default: return QString(); 145 | } 146 | } 147 | 148 | Protocol toProtocol(const QString &str) 149 | { 150 | for(int i=0; i 8 | * 9 | * ---- 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program; see the file COPYING. If not, write to 23 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301, USA. 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | namespace UFW 31 | { 32 | 33 | namespace Types 34 | { 35 | 36 | enum LogLevel 37 | { 38 | LOG_OFF, 39 | LOG_LOW, 40 | LOG_MEDIUM, 41 | LOG_HIGH, 42 | LOG_FULL, 43 | 44 | LOG_COUNT 45 | }; 46 | 47 | enum Logging 48 | { 49 | LOGGING_OFF, 50 | LOGGING_NEW, 51 | LOGGING_ALL, 52 | 53 | LOGGING_COUNT 54 | }; 55 | 56 | enum Policy 57 | { 58 | POLICY_ALLOW, 59 | POLICY_DENY, 60 | POLICY_REJECT, 61 | POLICY_LIMIT, 62 | 63 | POLICY_COUNT, 64 | POLICY_COUNT_DEFAULT=POLICY_COUNT-1 // No 'Limit' for defaults... 65 | }; 66 | 67 | enum PredefinedPort 68 | { 69 | PP_AMULE, 70 | PP_DELUGE, 71 | PP_KTORRENT, 72 | PP_NICOTINE, 73 | PP_QBITTORRNET, 74 | PP_TRANSMISSION, 75 | PP_IM_ICQ, 76 | PP_IM_JABBER, 77 | PP_IM_WLM, 78 | PP_IM_YAHOO, 79 | 80 | PP_FTP, 81 | PP_HTTP, 82 | PP_HTTPS, 83 | PP_IMAP, 84 | PP_IMAPS, 85 | PP_POP3, 86 | PP_POP3S, 87 | PP_SMTP, 88 | PP_NFS, 89 | PP_SAMBA, 90 | PP_SSH, 91 | PP_VNC, 92 | PP_ZEROCONF, 93 | PP_TELNET, 94 | PP_NTP, 95 | PP_CUPS, 96 | 97 | PP_COUNT 98 | }; 99 | 100 | enum Protocol 101 | { 102 | PROTO_BOTH, 103 | PROTO_TCP, 104 | PROTO_UDP, 105 | 106 | PROTO_COUNT 107 | }; 108 | 109 | extern QString toString(LogLevel level, bool ui=false); 110 | extern LogLevel toLogLevel(const QString &str); 111 | extern QString toString(Logging log, bool ui=false); 112 | extern Logging toLogging(const QString &str); 113 | extern QString toString(Policy policy, bool ui=false); 114 | extern Policy toPolicy(const QString &str); 115 | extern QString toString(PredefinedPort pp, bool ui=false); 116 | extern PredefinedPort toPredefinedPort(const QString &str); 117 | extern QString toString(Protocol proto, bool ui=false); 118 | extern Protocol toProtocol(const QString &str); 119 | 120 | } 121 | 122 | } 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /plugins/ufw/ufwclient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Alexis Lopes Zubeta 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "ufwclient.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | 31 | UfwClient::UfwClient(QObject *parent) : 32 | QObject(parent), 33 | m_isBusy(false), 34 | m_rulesModel(new RuleListModel(this)), 35 | m_logs(new LogListModel(this)) 36 | { 37 | // HACK: Quering the firewall status in this context 38 | // creates a segmentation fault error in some situations 39 | // due to an usage of the rootObject before it's 40 | // initialization. So, it's delayed a little. 41 | // refresh(); 42 | QTimer::singleShot(100, this, &UfwClient::refresh); 43 | QTimer::singleShot(2000, this, &UfwClient::refreshLogs); 44 | } 45 | 46 | void UfwClient::refresh() 47 | { 48 | queryStatus(); 49 | } 50 | 51 | bool UfwClient::enabled() const 52 | { 53 | return m_currentProfile.getEnabled(); 54 | } 55 | 56 | void UfwClient::setEnabled(const bool &enabled) 57 | { 58 | QVariantMap args { 59 | {"cmd", "setStatus"}, 60 | {"status", enabled}, 61 | }; 62 | 63 | KAuth::Action modifyAction = buildModifyAction(args); 64 | 65 | m_status = enabled ? i18n("Enabling the firewall...") : i18n("Disabling the firewall..."); 66 | m_isBusy = true; 67 | 68 | 69 | KAuth::ExecuteJob *job = modifyAction.execute(); 70 | connect(job, &KAuth::ExecuteJob::result, [this] (KJob *kjob) 71 | { 72 | auto job = qobject_cast(kjob); 73 | 74 | setStatus(""); 75 | setBusy(false); 76 | 77 | if (!job->error()) 78 | queryStatus(true, false); 79 | 80 | 81 | }); 82 | 83 | job->start(); 84 | } 85 | 86 | 87 | bool UfwClient::isBusy() const 88 | { 89 | return m_isBusy; 90 | } 91 | 92 | void UfwClient::queryStatus(bool readDefaults, bool listProfiles) 93 | { 94 | if (isBusy()) 95 | { 96 | qWarning() << "Ufw client is busy"; 97 | return; 98 | } 99 | 100 | QVariantMap args { 101 | {"defaults", readDefaults}, 102 | {"profiles", listProfiles}, 103 | }; 104 | 105 | KAuth::Action queryAction = buildQueryAction(args); 106 | 107 | setStatus(i18n("Querying firewall status...")); 108 | 109 | 110 | KAuth::ExecuteJob *job = queryAction.execute(); 111 | connect(job, &KAuth::ExecuteJob::result, [this] (KJob *kjob) 112 | { 113 | auto job = qobject_cast(kjob); 114 | 115 | if (!job->error()) 116 | { 117 | QByteArray response = job->data().value("response", "").toByteArray(); 118 | setProfile(UFW::Profile(response)); 119 | setStatus(""); 120 | } else { 121 | setStatus("There was an error in the backend! Please report it."); 122 | qWarning() << job->errorString(); 123 | } 124 | 125 | setBusy(false); 126 | }); 127 | 128 | job->start(); 129 | } 130 | 131 | void UfwClient::setDefaultIncomingPolicy(QString defaultIncomingPolicy) 132 | { 133 | const QString xmlArg = QStringLiteral("").arg(defaultIncomingPolicy); 134 | 135 | QVariantMap args { 136 | {"cmd","setDefaults"}, 137 | {"xml", xmlArg}, 138 | }; 139 | 140 | KAuth::Action modifyAction = buildModifyAction(args); 141 | m_status = i18n("Setting firewall default incomming policy..."); 142 | m_isBusy = true; 143 | 144 | KAuth::ExecuteJob *job = modifyAction.execute(); 145 | connect(job, &KAuth::ExecuteJob::result, [this] (KJob *kjob) 146 | { 147 | auto job = qobject_cast(kjob); 148 | 149 | setStatus(""); 150 | setBusy(false); 151 | 152 | if (!job->error()) 153 | queryStatus(true, false); 154 | 155 | 156 | }); 157 | 158 | job->start(); 159 | } 160 | 161 | void UfwClient::setDefaultOutgoingPolicy(QString defaultOutgoingPolicy) 162 | { 163 | const QString xmlArg = QStringLiteral("").arg(defaultOutgoingPolicy); 164 | 165 | QVariantMap args { 166 | {"cmd", "setDefaults"}, 167 | {"xml", xmlArg}, 168 | }; 169 | 170 | KAuth::Action modifyAction = buildModifyAction(args); 171 | m_status = i18n("Setting firewall default outgoing policy..."); 172 | m_isBusy = true; 173 | 174 | KAuth::ExecuteJob *job = modifyAction.execute(); 175 | connect(job, &KAuth::ExecuteJob::result, [this] (KJob *kjob) 176 | { 177 | auto job = qobject_cast(kjob); 178 | 179 | setStatus(""); 180 | setBusy(false); 181 | 182 | if (!job->error()) 183 | queryStatus(true, false); 184 | 185 | 186 | }); 187 | 188 | job->start(); 189 | } 190 | 191 | void UfwClient::setLogsAutoRefresh(bool logsAutoRefresh) 192 | { 193 | if (m_logsAutoRefresh == logsAutoRefresh) 194 | return; 195 | 196 | if (logsAutoRefresh) { 197 | connect(&m_logsRefreshTimer, &QTimer::timeout, this, &UfwClient::refreshLogs); 198 | m_logsRefreshTimer.setInterval(3000); 199 | m_logsRefreshTimer.start(); 200 | } else { 201 | disconnect(&m_logsRefreshTimer, &QTimer::timeout, this, &UfwClient::refreshLogs); 202 | m_logsRefreshTimer.stop(); 203 | } 204 | 205 | m_logsAutoRefresh = logsAutoRefresh; 206 | emit logsAutoRefreshChanged(m_logsAutoRefresh); 207 | } 208 | 209 | void UfwClient::refreshLogs() 210 | { 211 | KAuth::Action action("org.nomad.ufw.viewlog"); 212 | action.setHelperId("org.nomad.ufw"); 213 | 214 | QVariantMap args; 215 | if (m_rawLogs.size() > 0) 216 | args["lastLine"] = m_rawLogs.last(); 217 | 218 | action.setArguments(args); 219 | 220 | KAuth::ExecuteJob *job = action.execute(); 221 | connect(job, &KAuth::ExecuteJob::finished, [this] (KJob *kjob) 222 | { 223 | auto job = qobject_cast(kjob); 224 | 225 | if (!job->error()) 226 | { 227 | QStringList newLogs = job->data().value("lines", "").toStringList(); 228 | m_rawLogs.append(newLogs); 229 | m_logs->addRawLogs(newLogs); 230 | } else 231 | qWarning() << job->errorString(); 232 | 233 | setBusy(false); 234 | }); 235 | 236 | job->start(); 237 | } 238 | 239 | void UfwClient::setStatus(const QString &status) 240 | { 241 | m_status = status; 242 | emit statusChanged(m_status); 243 | } 244 | 245 | void UfwClient::setBusy(const bool &isBusy) 246 | { 247 | if (m_isBusy != isBusy) 248 | { 249 | m_isBusy = isBusy; 250 | emit isBusyChanged(isBusy); 251 | } 252 | } 253 | 254 | void UfwClient::setProfile(UFW::Profile profile) 255 | { 256 | auto oldProfile = m_currentProfile; 257 | m_currentProfile = profile; 258 | 259 | m_rulesModel->setProfile(m_currentProfile); 260 | if (m_currentProfile.getEnabled() != oldProfile.getEnabled()) 261 | emit enabledChanged(m_currentProfile.getEnabled()); 262 | 263 | if (m_currentProfile.getDefaultIncomingPolicy() != oldProfile.getDefaultIncomingPolicy()) { 264 | QString policy = UFW::Types::toString(m_currentProfile.getDefaultIncomingPolicy()); 265 | emit defaultIncomingPolicyChanged(policy); 266 | } 267 | 268 | if (m_currentProfile.getDefaultOutgoingPolicy() != oldProfile.getDefaultOutgoingPolicy()) { 269 | QString policy = UFW::Types::toString(m_currentProfile.getDefaultOutgoingPolicy()); 270 | emit defaultOutgoingPolicyChanged(policy); 271 | } 272 | } 273 | 274 | KAuth::Action UfwClient::buildQueryAction(const QVariantMap &arguments) 275 | { 276 | auto action = KAuth::Action("org.nomad.ufw.query"); 277 | action.setHelperId("org.nomad.ufw"); 278 | action.setArguments(arguments); 279 | 280 | return action; 281 | } 282 | 283 | KAuth::Action UfwClient::buildModifyAction(const QVariantMap &arguments) 284 | { 285 | auto action = KAuth::Action("org.nomad.ufw.modify"); 286 | action.setHelperId("org.nomad.ufw"); 287 | action.setArguments(arguments); 288 | 289 | return action; 290 | } 291 | 292 | QString UfwClient::status() const 293 | { 294 | return m_status; 295 | } 296 | 297 | RuleListModel *UfwClient::rules() const 298 | { 299 | return m_rulesModel; 300 | } 301 | 302 | RuleWrapper *UfwClient::getRule(int index) 303 | { 304 | auto rules = m_currentProfile.getRules(); 305 | 306 | if (index < 0 || index >= rules.count()) { 307 | return NULL; 308 | } 309 | 310 | auto rule = rules.at(index); 311 | rule.setPosition(index); 312 | RuleWrapper * wrapper = new RuleWrapper(rule, this); 313 | 314 | return wrapper; 315 | } 316 | 317 | void UfwClient::addRule(RuleWrapper *ruleWrapper) 318 | { 319 | if (ruleWrapper == NULL) { 320 | qWarning() << __FUNCTION__ << "NULL rule"; 321 | return; 322 | } 323 | 324 | UFW::Rule rule = ruleWrapper->getRule(); 325 | 326 | QVariantMap args { 327 | {"cmd", "addRules"}, 328 | {"count",1}, 329 | {"xml0", rule.toXml()}, 330 | }; 331 | 332 | KAuth::Action modifyAction = buildModifyAction(args); 333 | setStatus(i18n("Adding rule...")); 334 | 335 | KAuth::ExecuteJob *job = modifyAction.execute(); 336 | connect(job, &KAuth::ExecuteJob::result, [this] (KJob *kjob) 337 | { 338 | auto job = qobject_cast(kjob); 339 | 340 | if (!job->error()) 341 | { 342 | QByteArray response = job->data().value("response", "").toByteArray(); 343 | setProfile(UFW::Profile(response)); 344 | } else 345 | qWarning() << job->errorString(); 346 | 347 | setStatus(""); 348 | setBusy(false); 349 | }); 350 | 351 | job->start(); 352 | } 353 | 354 | void UfwClient::removeRule(int index) 355 | { 356 | if (index < 0 || index >= m_currentProfile.getRules().count()) { 357 | qWarning() << __FUNCTION__ << "invalid rule index"; 358 | return; 359 | } 360 | 361 | // Correct index 362 | index += 1; 363 | 364 | QVariantMap args { 365 | {"cmd", "removeRule"}, 366 | {"index", QString::number(index)}, 367 | }; 368 | 369 | KAuth::Action modifyAction = buildModifyAction(args); 370 | setStatus(i18n("Removing rule from firewall...")); 371 | 372 | KAuth::ExecuteJob *job = modifyAction.execute(); 373 | connect(job, &KAuth::ExecuteJob::result, [this] (KJob *kjob) 374 | { 375 | auto job = qobject_cast(kjob); 376 | 377 | if (!job->error()) 378 | { 379 | QByteArray response = job->data().value("response", "").toByteArray(); 380 | setProfile(UFW::Profile(response)); 381 | } else 382 | qWarning() << job->errorString(); 383 | 384 | setStatus(""); 385 | setBusy(false); 386 | }); 387 | 388 | job->start(); 389 | } 390 | 391 | void UfwClient::updateRule(RuleWrapper *ruleWrapper) 392 | { 393 | if (ruleWrapper == NULL) { 394 | qWarning() << __FUNCTION__ << "NULL rule"; 395 | return; 396 | } 397 | 398 | UFW::Rule rule = ruleWrapper->getRule(); 399 | 400 | rule.setPosition(rule.getPosition() + 1); 401 | QVariantMap args { 402 | {"cmd", "editRule"}, 403 | {"xml", rule.toXml()}, 404 | }; 405 | 406 | KAuth::Action modifyAction = buildModifyAction(args); 407 | setStatus(i18n("Updating rule...")); 408 | 409 | KAuth::ExecuteJob *job = modifyAction.execute(); 410 | connect(job, &KAuth::ExecuteJob::result, [this] (KJob *kjob) 411 | { 412 | auto job = qobject_cast(kjob); 413 | 414 | if (!job->error()) 415 | { 416 | QByteArray response = job->data().value("response", "").toByteArray(); 417 | setProfile(UFW::Profile(response)); 418 | } else 419 | qWarning() << job->errorString(); 420 | 421 | setStatus(""); 422 | setBusy(false); 423 | }); 424 | 425 | job->start(); 426 | } 427 | 428 | void UfwClient::moveRule(int from, int to) 429 | { 430 | QList rules = m_currentProfile.getRules(); 431 | if (from < 0 || from >= rules.count()) { 432 | qWarning() << __FUNCTION__ << "invalid from index"; 433 | return; 434 | } 435 | 436 | if (to < 0 || to >= rules.count()) { 437 | qWarning() << __FUNCTION__ << "invalid to index"; 438 | return; 439 | } 440 | // Correct indices 441 | from += 1; 442 | to += 1; 443 | 444 | QVariantMap args { 445 | {"cmd", "moveRule"}, 446 | {"from", from}, 447 | {"to", to}, 448 | }; 449 | 450 | KAuth::Action modifyAction = buildModifyAction(args); 451 | setStatus(i18n("Moving rule in firewall...")); 452 | 453 | KAuth::ExecuteJob *job = modifyAction.execute(); 454 | connect(job, &KAuth::ExecuteJob::finished, [this] (KJob *kjob) 455 | { 456 | auto job = qobject_cast(kjob); 457 | 458 | if (!job->error()) 459 | { 460 | QByteArray response = job->data().value("response", "").toByteArray(); 461 | setProfile(UFW::Profile(response)); 462 | } else 463 | qWarning() << job->errorString(); 464 | 465 | setStatus(""); 466 | setBusy(false); 467 | }); 468 | 469 | job->start(); 470 | } 471 | 472 | QStringList UfwClient::getKnownProtocols() 473 | { 474 | return { i18n("Any"), "TCP", "UDP" }; 475 | } 476 | 477 | QStringList UfwClient::getKnownInterfaces() 478 | { 479 | QStringList interfaces_names({i18n("Any")}); 480 | 481 | QList interfaces = QNetworkInterface::allInterfaces(); 482 | for (QNetworkInterface iface : qAsConst(interfaces)) 483 | interfaces_names << iface.name(); 484 | 485 | return interfaces_names; 486 | } 487 | 488 | QString UfwClient::defaultIncomingPolicy() const 489 | { 490 | auto policy_t = m_currentProfile.getDefaultIncomingPolicy(); 491 | return UFW::Types::toString(policy_t); 492 | } 493 | 494 | QString UfwClient::defaultOutgoingPolicy() const 495 | { 496 | auto policy_t = m_currentProfile.getDefaultOutgoingPolicy(); 497 | return UFW::Types::toString(policy_t); 498 | } 499 | 500 | LogListModel *UfwClient::logs() 501 | { 502 | return m_logs; 503 | } 504 | 505 | 506 | bool UfwClient::logsAutoRefresh() const 507 | { 508 | return m_logsAutoRefresh; 509 | } 510 | -------------------------------------------------------------------------------- /plugins/ufw/ufwclient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Alexis Lopes Zubeta 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #ifndef UFWCLIENT_H 22 | #define UFWCLIENT_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | #include "profile.h" 31 | #include "rulelistmodel.h" 32 | #include "loglistmodel.h" 33 | 34 | class UfwClient : public QObject 35 | { 36 | Q_OBJECT 37 | Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) 38 | Q_PROPERTY(bool isBusy READ isBusy NOTIFY isBusyChanged) 39 | Q_PROPERTY(QString status READ status NOTIFY statusChanged) 40 | Q_PROPERTY(QString defaultIncomingPolicy READ defaultIncomingPolicy WRITE setDefaultIncomingPolicy NOTIFY defaultIncomingPolicyChanged) 41 | Q_PROPERTY(QString defaultOutgoingPolicy READ defaultOutgoingPolicy WRITE setDefaultOutgoingPolicy NOTIFY defaultOutgoingPolicyChanged) 42 | Q_PROPERTY(bool logsAutoRefresh READ logsAutoRefresh WRITE setLogsAutoRefresh NOTIFY logsAutoRefreshChanged) 43 | public: 44 | explicit UfwClient(QObject *parent = nullptr); 45 | 46 | Q_INVOKABLE void refresh(); 47 | Q_INVOKABLE RuleListModel* rules() const; 48 | Q_INVOKABLE RuleWrapper* getRule(int index); 49 | Q_INVOKABLE void addRule(RuleWrapper * rule); 50 | Q_INVOKABLE void removeRule(int index); 51 | Q_INVOKABLE void updateRule(RuleWrapper * rule); 52 | Q_INVOKABLE void moveRule(int from, int to); 53 | 54 | Q_INVOKABLE static QStringList getKnownProtocols(); 55 | Q_INVOKABLE static QStringList getKnownInterfaces(); 56 | 57 | bool enabled() const; 58 | bool isBusy() const; 59 | QString status() const; 60 | QString defaultIncomingPolicy() const; 61 | QString defaultOutgoingPolicy() const; 62 | 63 | Q_INVOKABLE LogListModel* logs(); 64 | bool logsAutoRefresh() const; 65 | 66 | signals: 67 | void isBusyChanged(const bool isBusy); 68 | void enabledChanged(const bool enabled); 69 | void statusChanged(const QString &status); 70 | 71 | void defaultIncomingPolicyChanged(QString defaultIncomingPolicy); 72 | void defaultOutgoingPolicyChanged(QString defaultOutgoingPolicy); 73 | 74 | 75 | void logsAutoRefreshChanged(bool logsAutoRefresh); 76 | 77 | public slots: 78 | void setEnabled(const bool &enabled); 79 | void queryStatus(bool readDefaults=true, bool listProfiles=true); 80 | void setDefaultIncomingPolicy(QString defaultIncomingPolicy); 81 | void setDefaultOutgoingPolicy(QString defaultOutgoingPolicy); 82 | 83 | void setLogsAutoRefresh(bool logsAutoRefresh); 84 | 85 | protected slots: 86 | void refreshLogs(); 87 | 88 | protected: 89 | void setStatus(const QString &status); 90 | void setBusy(const bool &busy); 91 | void setProfile(UFW::Profile profile); 92 | KAuth::Action buildQueryAction(const QVariantMap &arguments); 93 | KAuth::Action buildModifyAction(const QVariantMap &arguments); 94 | 95 | private: 96 | QString m_status; 97 | QStringList m_rawLogs; 98 | bool m_isBusy; 99 | UFW::Profile m_currentProfile; 100 | RuleListModel* m_rulesModel; 101 | LogListModel* m_logs; 102 | QTimer m_logsRefreshTimer; 103 | // UFW::Blocker *blocker; 104 | bool m_logsAutoRefresh; 105 | }; 106 | 107 | #endif // UFWCLIENT_H 108 | -------------------------------------------------------------------------------- /plugins/ufw/ufwplugin.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Alexis Lopes Zubeta 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "ufwplugin.h" 22 | #include "ufwclient.h" 23 | #include "rulelistmodel.h" 24 | #include "rulewrapper.h" 25 | #include "loglistmodel.h" 26 | 27 | #include 28 | 29 | void UfwPlugin::registerTypes(const char *uri) 30 | { 31 | Q_ASSERT(uri == QLatin1String("org.nomad.ufw")); 32 | 33 | qmlRegisterType(uri, 1, 0, "UfwClient"); 34 | qmlRegisterType(uri, 1, 0, "RuleListModel"); 35 | qmlRegisterType(uri, 1, 0, "Rule"); 36 | qmlRegisterUncreatableType(uri, 1, 0, "LogListModel", "Only created from the UfwClient."); 37 | } 38 | -------------------------------------------------------------------------------- /plugins/ufw/ufwplugin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Alexis Lopes Zubeta 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #ifndef UFWPLUGIN_H 22 | #define UFWPLUGIN_H 23 | 24 | #include 25 | #include 26 | 27 | class UfwPlugin : public QQmlExtensionPlugin 28 | { 29 | Q_OBJECT 30 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") 31 | 32 | public: 33 | virtual void registerTypes(const char *uri); 34 | }; 35 | 36 | #endif // UFWPLUGIN_H 37 | --------------------------------------------------------------------------------