Package: release.debian.org
Severity: normal
User: release.debian....@packages.debian.org
Usertags: unblock

Please unblock package ufw

It seems that adduser 3.133 has caused problems for a lot of packages in sid,
including ufw. See:

https://piuparts.debian.org/sid/fail/adduser_3.133.log
https://piuparts.debian.org/sid/fail/
https://piuparts.debian.org/sid/fail/ufw_0.36.2-1.log
https://piuparts.debian.org/sid/fail/...

In the case of ufw, it ships a logrotate file and logrotate gets installed,
which pulls in adduser, but adduser can't be removed and piuparts fails:

0m18.6s DEBUG: Starting command: ['chroot', 
'/srv/piuparts.debian.org/tmp/tmpwv4fmpa7', 'apt-get', 'install', '-y', 
'logrotate']
0m19.9s DUMP:
  Reading package lists...
  Building dependency tree...
  Reading state information...
  The following additional packages will be installed:
    adduser cron cron-daemon-common libpopt0 sensible-utils
...
m20.2s ERROR: Command failed (status=1): ['chroot', 
'/srv/piuparts.debian.org/tmp/tmpwv4fmpa7', 'dpkg', '--purge', 'adduser', 
'cron', 'cron-daemon-common', 'libpopt0:amd64', 'logrotate', 'sensible-utils']
  dpkg: error processing package adduser (--purge):
   this is a protected package; it should not be removed
...

As mentioned, there seem to be several packages in this state. ufw has shipped
a logrotate file for years and this isn't new to ufw 0.36.2-1. 

[ Reason ]
ufw did not cause adduser to be unremovable, and adduser being unremovable
should not affect ufw's migration.

[ Impact ]
Bug fixes and translations will not be available in bookworm (I am upstream ufw
and I cut 0.36.2 specifically for bookworm users).

[ Tests ]
Build tests (unit and functional) and autopkgtests pass.

[ Risks ]
Leaf package.

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing


unblock ufw/0.36.2-1
diff -Nru ufw-0.36.1/ChangeLog ufw-0.36.2/ChangeLog
--- ufw-0.36.1/ChangeLog        2021-09-18 20:29:52.000000000 -0500
+++ ufw-0.36.2/ChangeLog        2023-05-18 08:45:35.000000000 -0500
@@ -1,3 +1,23 @@
+ufw (0.36.2) RELEASED; urgency=medium
+
+  * src/ufw-init-functions: set default policy after loading rules. Thanks to
+    Mauricio Faria de Oliveira. (LP: #1946804)
+  * doc/ufw.8:
+    - document 'insert' and 'prepend' can't be used to update comments
+      (LP: #1927737)
+  * src/backend_iptables.py: remove unreachable code (LP: #1927734)
+  * src/util.py:
+    - properly parse /proc/pid/stat for WSL (LP: #2015645)
+    - mitigate odd length string with unhexlify (Closes: 1034568)
+    - support vrrp protocol (LP: #1996636)
+  * add locales/po/ro.po. Thanks Remus-Gabriel Chelu (Closes: 1034119)
+  * add '-h' and show help with no args (LP: #1965462)
+  * src/backend.py: add get_rules_ipv4() and get_rules_ipv6() (LP: #1951018)
+  * tests/check-requirements: update for python 3.10+
+  * tests/root: normalize 'ACCEPT {all,tcp}' and 'ACCEPT N' for newer systems
+
+ -- Jamie Strandboge <jdstr...@ubuntu.com>  Thu, 18 May 2023 08:45:30 -0500
+
 ufw (0.36.1) RELEASED; urgency=medium
 
   * snap packaging updates:
diff -Nru ufw-0.36.1/debian/changelog ufw-0.36.2/debian/changelog
--- ufw-0.36.1/debian/changelog 2022-10-15 05:54:27.000000000 -0500
+++ ufw-0.36.2/debian/changelog 2023-05-18 09:03:07.000000000 -0500
@@ -1,3 +1,30 @@
+ufw (0.36.2-1) unstable; urgency=medium
+
+  * New upstream release (LP: #1946804, LP: #1927737, LP: #1927734,
+    LP: #2015645, LP: #1996636, LP: #1965462, LP: #1951018, Closes: 1034568,
+    Closes: 1034119). Drop the following (included upstream):
+    - 0002-fix-copyright.patch
+    - 0003-python3-versions.patch
+    - 0004-set-default-policy-after-load.patch
+  * Remaining changes:
+    - 0001-optimize-boot.patch
+  * add new debian/po/ro.po. Thanks Remus-Gabriel Chelu (Closes: 1033758)
+  * debian/control:
+    - Breaks with iptables-persistent and netfilter-persistent. When ufw is
+      installed, it is not enabled by default, so it doesn't interfere with
+      other firewall software (until it is enabled). In contrast,
+      iptables-persistent and netfilter-persistent install enabled, which
+      interferes with ufw. Add a breaks on these to avoid them being
+      co-installed with ufw (and causing problems for users).
+    - use Python-Version instead of XB-Python-Version
+    - remove Depends on obsolete lsb-base
+  * ufw.lintian-overrides:
+    - update for breaks-without-version iptables-persistent and
+      netfilter-persistent
+    - update for newer lintian
+
+ -- Jamie Strandboge <jdstr...@ubuntu.com>  Thu, 18 May 2023 14:03:07 +0000
+
 ufw (0.36.1-4.1) unstable; urgency=medium
 
   * Non-maintainer upload.
diff -Nru ufw-0.36.1/debian/control ufw-0.36.2/debian/control
--- ufw-0.36.1/debian/control   2021-09-19 00:46:12.000000000 -0500
+++ ufw-0.36.2/debian/control   2023-05-16 09:37:21.000000000 -0500
@@ -13,7 +13,7 @@
  po-debconf,
  python3 (>= 3.2),
  python3-distutils
-Standards-Version: 4.6.0.1
+Standards-Version: 4.6.2
 Homepage: https://launchpad.net/ufw
 Vcs-Browser: https://git.launchpad.net/ufw?h=debian/master
 Vcs-Git: https://git.launchpad.net/ufw -b debian/master
@@ -23,11 +23,11 @@
 Suggests: rsyslog
 Depends:
  iptables,
- lsb-base (>= 3.0-6),
  ucf,
  ${python3:Depends},
  ${misc:Depends}
-XB-Python-Version: ${python3:Versions}
+Breaks: iptables-persistent, netfilter-persistent
+Python-Version: ${python3:Versions}
 Description: program for managing a Netfilter firewall
  The Uncomplicated FireWall is a front-end for iptables, to make managing a
  Netfilter firewall easier. It provides a command line interface with syntax
diff -Nru ufw-0.36.1/debian/patches/0002-fix-copyright.patch 
ufw-0.36.2/debian/patches/0002-fix-copyright.patch
--- ufw-0.36.1/debian/patches/0002-fix-copyright.patch  2021-09-19 
00:46:12.000000000 -0500
+++ ufw-0.36.2/debian/patches/0002-fix-copyright.patch  1969-12-31 
18:00:00.000000000 -0600
@@ -1,28 +0,0 @@
-commit b1d840a4a23bd586059d6654fb60a42114ae7b92
-Author: Jamie Strandboge <jdstr...@ubuntu.com>
-Date:   Sun Sep 19 01:09:36 2021 -0500
-
-    src/ufw: update copyright year
-
-diff --git a/src/ufw b/src/ufw
-index 115d294..7d72395 100755
---- a/src/ufw
-+++ b/src/ufw
-@@ -2,7 +2,7 @@
- #
- # ufw: front-end for Linux firewalling (cli)
- #
--# Copyright 2008-2018 Canonical Ltd.
-+# Copyright 2008-2021 Canonical Ltd.
- #
- #    This program is free software: you can redistribute it and/or modify
- #    it under the terms of the GNU General Public License version 3,
-@@ -108,7 +108,7 @@ if __name__ == "__main__":
-         sys.exit(0)
-     elif pr.action == "version" or pr.action == "--version":
-         msg(ufw.common.programName + " " + version)
--        msg("Copyright 2008-2018 Canonical Ltd.")
-+        msg("Copyright 2008-2021 Canonical Ltd.")
-         sys.exit(0)
- 
-     try:
diff -Nru ufw-0.36.1/debian/patches/0003-python3-versions.patch 
ufw-0.36.2/debian/patches/0003-python3-versions.patch
--- ufw-0.36.1/debian/patches/0003-python3-versions.patch       2021-09-19 
00:46:12.000000000 -0500
+++ ufw-0.36.2/debian/patches/0003-python3-versions.patch       1969-12-31 
18:00:00.000000000 -0600
@@ -1,15 +0,0 @@
-Author: Matthias Klose <d...@debian.org>
-Description: Fix python version check for Python >= 3.9
-Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=975912
-Forwarded: yes
---- a/tests/check-requirements
-+++ b/tests/check-requirements
-@@ -59,7 +59,7 @@ for exe in python3 python2 python ; do
-         echo "pass (binary: $exe, version: $v, py2)"
-         found_python="yes"
-         break
--    elif echo "$v" | grep -q "^3.[2-8]"; then
-+    elif echo "$v" | grep -q "^3.[1-9][0-9]*"; then
-         echo "pass (binary: $exe, version: $v, py3)"
-         found_python="yes"
-         break
diff -Nru ufw-0.36.1/debian/patches/0004-set-default-policy-after-load.patch 
ufw-0.36.2/debian/patches/0004-set-default-policy-after-load.patch
--- ufw-0.36.1/debian/patches/0004-set-default-policy-after-load.patch  
2021-10-13 14:00:26.000000000 -0500
+++ ufw-0.36.2/debian/patches/0004-set-default-policy-after-load.patch  
1969-12-31 18:00:00.000000000 -0600
@@ -1,93 +0,0 @@
-Origin: upstream, 
https://git.launchpad.net/ufw/commit/?id=4d25bd6635a493ae10c1984bfe16fb31e3903198
-Bug-Ubuntu: https://bugs.launchpad.net/bugs/1946804
-From: Mauricio Faria de Oliveira <m...@canonical.com>
-Date: Tue, 12 Oct 2021 18:57:40 -0300
-Subject: [PATCH] src/ufw-init-functions: set default policy after loading
- rules
-
-If default input policy of DROP (default setting in ufw) is set
-before loading rules to allow a network root filesystem to work,
-it freezes before loading them, and the boot process stalls.
-
-Just set default policy after loading rules, as the snippet for
-ip[6]tables-restore has -n/--noflush, which doesn't flush other
-rules in the builtin chains.
-
-The output of iptables -L is identical before/after.
-
-https://bugs.launchpad.net/bugs/1946804
-
-Signed-off-by: Mauricio Faria de Oliveira <m...@canonical.com>
----
- src/ufw-init-functions | 48 ++++++++++++++++++++++--------------------
- 1 file changed, 25 insertions(+), 23 deletions(-)
-
-diff --git a/src/ufw-init-functions b/src/ufw-init-functions
-index feac8e203c1d..f0dd7f59f4c2 100755
---- a/src/ufw-init-functions
-+++ b/src/ufw-init-functions
-@@ -168,29 +168,6 @@ ufw_start() {
-             AFTER_RULES="$RULES_PATH/after${type}.rules"
-             USER_RULES="$USER_PATH/user${type}.rules"
- 
--            # set the default policy
--            input_pol="$DEFAULT_INPUT_POLICY"
--            if [ "$DEFAULT_INPUT_POLICY" = "REJECT" ]; then
--                input_pol="DROP"
--            fi
--
--            output_pol="$DEFAULT_OUTPUT_POLICY"
--            if [ "$DEFAULT_OUTPUT_POLICY" = "REJECT" ]; then
--                output_pol="DROP"
--            fi
--
--            forward_pol="$DEFAULT_FORWARD_POLICY"
--            if [ "$DEFAULT_FORWARD_POLICY" = "REJECT" ]; then
--                forward_pol="DROP"
--            fi
--
--            printf "*filter\n"\
--"# builtin chains\n"\
--":INPUT %s [0:0]\n"\
--":FORWARD %s [0:0]\n"\
--":OUTPUT %s [0:0]\n"\
--"COMMIT\n" $input_pol $forward_pol $output_pol | $exe-restore -n || 
error="yes"
--
-             # flush the chains (if they exist)
-             if $exe -L ufw${type}-before-logging-input -n >/dev/null 2>&1 ; 
then
-                 delete_chains $type || error="yes"
-@@ -378,6 +355,31 @@ ufw_start() {
-                 out="${out}\nCouldn't find '$USER_RULES'"
-                 error="yes"
-             fi
-+
-+            # set the default policy
-+            # (do this after loading rules so not to break
-+            # network rootfs w/ INPUT DROP during ufw init.)
-+            input_pol="$DEFAULT_INPUT_POLICY"
-+            if [ "$DEFAULT_INPUT_POLICY" = "REJECT" ]; then
-+                input_pol="DROP"
-+            fi
-+
-+            output_pol="$DEFAULT_OUTPUT_POLICY"
-+            if [ "$DEFAULT_OUTPUT_POLICY" = "REJECT" ]; then
-+                output_pol="DROP"
-+            fi
-+
-+            forward_pol="$DEFAULT_FORWARD_POLICY"
-+            if [ "$DEFAULT_FORWARD_POLICY" = "REJECT" ]; then
-+                forward_pol="DROP"
-+            fi
-+
-+            printf "*filter\n"\
-+"# builtin chains\n"\
-+":INPUT %s [0:0]\n"\
-+":FORWARD %s [0:0]\n"\
-+":OUTPUT %s [0:0]\n"\
-+"COMMIT\n" $input_pol $forward_pol $output_pol | $exe-restore -n || 
error="yes"
-         done
- 
-         if [ ! -z "$IPT_SYSCTL" ] && [ -s "$IPT_SYSCTL" ]; then
--- 
-2.30.2
-
diff -Nru ufw-0.36.1/debian/patches/series ufw-0.36.2/debian/patches/series
--- ufw-0.36.1/debian/patches/series    2021-10-13 14:02:20.000000000 -0500
+++ ufw-0.36.2/debian/patches/series    2023-05-16 09:03:37.000000000 -0500
@@ -1,4 +1 @@
 0001-optimize-boot.patch
-0002-fix-copyright.patch
-0003-python3-versions.patch
-0004-set-default-policy-after-load.patch
diff -Nru ufw-0.36.1/debian/po/ro.po ufw-0.36.2/debian/po/ro.po
--- ufw-0.36.1/debian/po/ro.po  1969-12-31 18:00:00.000000000 -0600
+++ ufw-0.36.2/debian/po/ro.po  2023-05-16 08:59:14.000000000 -0500
@@ -0,0 +1,125 @@
+# Mesajele în limba română pentru pachetul ufw.
+# Romanian translation of ufw.
+# Copyright © 2023 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the ufw package.
+#
+# Remus-Gabriel Chelu <remusgabriel.ch...@disroot.org>, 2023.
+#
+# Cronologia traducerii fișierului „ufw”:
+# Traducerea inițială, făcută de R-GC, pentru versiunea ufw 
0.36.1-4.1(2009-06-16).
+# Actualizare a traducerii pentru versiunea Y, făcută de X, Y(anul).
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ufw 0.36.1-4.1\n"
+"Report-Msgid-Bugs-To: u...@packages.debian.org\n"
+"POT-Creation-Date: 2009-06-16 23:11+0100\n"
+"PO-Revision-Date: 2023-03-26 21:16+0200\n"
+"Last-Translator: Remus-Gabriel Chelu <remusgabriel.ch...@disroot.org>\n"
+"Language-Team: Romanian <debian-l10n-roman...@lists.debian.org>\n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n==0 || (n!=1 && n%100>=1 && "
+"n%100<=19) ? 1 : 2);\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
+"X-Generator: Poedit 3.2.2\n"
+
+#. Type: error
+#. Description
+#: ../templates:2001
+msgid "Existing configuration found"
+msgstr "S-a găsit o configurație existentă"
+
+#. Type: error
+#. Description
+#: ../templates:2001
+msgid ""
+"An existing configuration for ufw has been found. Existing rules must be "
+"managed manually."
+msgstr ""
+"O configurație existentă pentru «ufw» a fost găsită. Regulile existente 
trebuie "
+"gestionate manual."
+
+#. Type: error
+#. Description
+#: ../templates:2001
+msgid "You should read the ufw(8) manpage for details about ufw configuration."
+msgstr ""
+"Ar trebui să citiți pagina de manual ufw(8) pentru detalii despre 
configurarea "
+"„ufw”."
+
+#. Type: boolean
+#. Description
+#: ../templates:3001
+msgid "Start ufw automatically?"
+msgstr "Doriți să porniți automat serviciul «ufw»?"
+
+#. Type: boolean
+#. Description
+#: ../templates:3001
+msgid ""
+"If you choose this option, the rules you are about to set will be enabled "
+"during system startup so that this host is protected as early as possible."
+msgstr ""
+"Dacă alegeți această opțiune, regulile pe care urmează să le stabiliți vor fi 
"
+"activate în timpul pornirii sistemului, astfel încât această gazdă să fie "
+"protejată cât mai curând posibil."
+
+#. Type: boolean
+#. Description
+#: ../templates:3001
+msgid "To protect this host immediately, you must start ufw manually."
+msgstr ""
+"Pentru a proteja această gazdă imediat, trebuie să porniți manual serviciul "
+"«ufw»."
+
+#. Type: multiselect
+#. Description
+#: ../templates:4001
+msgid "Authorized services:"
+msgstr "Servicii autorizate:"
+
+#. Type: multiselect
+#. Description
+#: ../templates:4001
+msgid ""
+"Please choose the services that should be available for incoming connections."
+msgstr ""
+"Alegeți serviciile care ar trebui să fie disponibile pentru conexiunile de "
+"intrare."
+
+#. Type: multiselect
+#. Description
+#: ../templates:4001
+msgid "Other services may be specified in the next configuration step."
+msgstr "Alte servicii pot fi specificate în următorul pas de configurare."
+
+#. Type: string
+#. Description
+#: ../templates:5001
+msgid "Additional authorized services:"
+msgstr "Servicii suplimentare autorizate:"
+
+#. Type: string
+#. Description
+#: ../templates:5001
+msgid ""
+"Please enter a space separated list of any additional ports you would like to 
"
+"open. You may use a service name (as found in /etc/services), a port number, 
or "
+"a port number with protocol."
+msgstr ""
+"Introduceți o listă separată de spații cu porturile suplimentare pe care 
doriți "
+"să le deschideți. Puteți utiliza un nume de serviciu (cum se găsește în 
„/etc/"
+"services”), un număr de port sau un număr de port cu protocol."
+
+#. Type: string
+#. Description
+#: ../templates:5001
+msgid ""
+"Example: to allow a web server, port 53 and tcp port 22, you should enter 
\"www "
+"53 22/tcp\"."
+msgstr ""
+"Exemplu: pentru a permite un server web, portul 53 și portul tcp 22, ar 
trebui "
+"să introduceți „www 53 22/tcp”."
diff -Nru ufw-0.36.1/debian/ufw.lintian-overrides 
ufw-0.36.2/debian/ufw.lintian-overrides
--- ufw-0.36.1/debian/ufw.lintian-overrides     2021-09-19 00:33:52.000000000 
-0500
+++ ufw-0.36.2/debian/ufw.lintian-overrides     2023-05-16 09:46:12.000000000 
-0500
@@ -1,8 +1,11 @@
 # These are intentionally not executable
-ufw binary: script-not-executable usr/share/ufw/after.init
-ufw binary: script-not-executable usr/share/ufw/before.init
+ufw: script-not-executable [usr/share/ufw/after.init]
+ufw: script-not-executable [usr/share/ufw/before.init]
 # Don't complain about 'ufw allow' rules
-ufw binary: typo-in-manual-page usr/share/man/man8/ufw.8.gz "allow to" "allow 
one to"
-ufw binary: spelling-error-in-changelog "allow to" "allow one to"
+ufw: spelling-error-in-changelog "allow to" "allow one to"
+ufw: mismatched-override typo-in-manual-page usr/share/man/man8/ufw.8.gz 
"allow to" "allow one to" [usr/share/lintian/overrides/ufw:5]
 # Don't complain about the ufw-framework man page, it gives additional details
-ufw binary: spare-manual-page usr/share/man/man8/ufw-framework.8.gz
+ufw: spare-manual-page usr/share/man/man8/ufw-framework.8.gz
+# Don't complain about breaks-without-version since we want to break on all
+ufw: breaks-without-version iptables-persistent
+ufw: breaks-without-version netfilter-persistent
diff -Nru ufw-0.36.1/doc/systemd.example ufw-0.36.2/doc/systemd.example
--- ufw-0.36.1/doc/systemd.example      2021-09-18 19:50:19.000000000 -0500
+++ ufw-0.36.2/doc/systemd.example      2023-05-18 08:07:39.000000000 -0500
@@ -1,8 +1,9 @@
 [Unit]
 Description=Uncomplicated firewall
-DefaultDependencies=no
-Wants=network-pre.target
+Documentation=man:ufw(8)
 Before=network-pre.target
+Wants=network-pre.target
+Conflicts=iptables.service ip6tables.service nftables.service firewalld.service
 
 [Service]
 Type=oneshot
diff -Nru ufw-0.36.1/doc/ufw.8 ufw-0.36.2/doc/ufw.8
--- ufw-0.36.1/doc/ufw.8        2021-09-18 20:19:03.000000000 -0500
+++ ufw-0.36.2/doc/ufw.8        2023-05-18 08:07:39.000000000 -0500
@@ -1,4 +1,4 @@
-.TH UFW: "8" "" "September 2021" "September 2021"
+.TH UFW: "8" "" "May 2023" "May 2023"
 
 .SH NAME
 ufw \- program for managing a netfilter firewall
@@ -125,7 +125,8 @@
 
 Both syntaxes support specifying a comment for the rule. For existing rules,
 specifying a different comment updates the comment and specifying '' removes
-the comment.
+the comment (note, 'insert' and 'prepend' cannot be used to update the
+comment).
 
 Example rules using the simple syntax:
 
@@ -199,6 +200,7 @@
   ah      valid without port number
   esp     valid without port number
   gre     valid without port number
+  vrrp    valid without port number
   ipv6    valid for IPv4 addresses and without port number
   igmp    valid for IPv4 addresses and without port number
 
@@ -565,6 +567,11 @@
   ufw allow to 10.0.0.1 proto ah
   ufw allow to 10.0.0.1 from 10.4.0.0/16 proto ah
 .PP
+keepalived is supported by using the 'vrrp' ('112') protocol. This protocol
+can only be used with the full syntax. For example:
+
+  ufw allow to 224.0.0.0/24 from 10.0.0.1 proto vrrp
+.PP
 In addition to the command\-line interface, \fBufw\fR also provides a
 framework which allows administrators to modify default behavior as well as
 take full advantage of netfilter. See the \fBufw\-framework\fR manual page for
@@ -576,4 +583,4 @@
 
 .SH AUTHOR
 .PP
-ufw is Copyright 2008-2021, Canonical Ltd.
+ufw is Copyright 2008-2023, Canonical Ltd.
diff -Nru ufw-0.36.1/doc/ufw-framework.8 ufw-0.36.2/doc/ufw-framework.8
--- ufw-0.36.1/doc/ufw-framework.8      2021-09-18 20:19:03.000000000 -0500
+++ ufw-0.36.2/doc/ufw-framework.8      2023-05-16 09:51:25.000000000 -0500
@@ -1,4 +1,4 @@
-.TH "UFW FRAMEWORK" "8" "" "September 2021" "September 2021"
+.TH "UFW FRAMEWORK" "8" "" "May 2023" "May 2023"
 
 .SH NAME
 ufw\-framework \- using the ufw framework
@@ -318,4 +318,4 @@
 
 .SH AUTHOR
 .PP
-ufw is Copyright 2008-2021, Canonical Ltd.
+ufw is Copyright 2008-2023, Canonical Ltd.
diff -Nru ufw-0.36.1/doc/ufw-on-snappy.8 ufw-0.36.2/doc/ufw-on-snappy.8
--- ufw-0.36.1/doc/ufw-on-snappy.8      2021-09-18 20:19:03.000000000 -0500
+++ ufw-0.36.2/doc/ufw-on-snappy.8      2023-05-16 09:51:25.000000000 -0500
@@ -1,4 +1,4 @@
-.TH "UFW ON SNAPPY" "8" "" "September 2021" "September 2021"
+.TH "UFW ON SNAPPY" "8" "" "May 2023" "May 2023"
 
 .SH NAME
 ufw snap \- using ufw as a snap
@@ -71,4 +71,4 @@
 
 .SH AUTHOR
 .PP
-ufw is Copyright 2008-2021, Canonical Ltd.
+ufw is Copyright 2008-2023, Canonical Ltd.
diff -Nru ufw-0.36.1/locales/po/ro.po ufw-0.36.2/locales/po/ro.po
--- ufw-0.36.1/locales/po/ro.po 1969-12-31 18:00:00.000000000 -0600
+++ ufw-0.36.2/locales/po/ro.po 2023-05-16 09:51:25.000000000 -0500
@@ -0,0 +1,989 @@
+# Mesajele în limba română pentru pachetul ufw.
+# Romanian translation of ufw.
+# Copyright © 2023 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the ufw package.
+#
+# Remus-Gabriel Chelu <remusgabriel.ch...@disroot.org>, 2023.
+#
+# Cronologia traducerii fișierului „ufw”:
+# Traducerea inițială, făcută de R-GC, pentru versiunea ufw 
0.36.1-4.1(2018-12-14).
+# Actualizare a traducerii pentru versiunea Y, făcută de X, Y(anul).
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ufw 0.36.1-4.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-12-14 10:02-0600\n"
+"PO-Revision-Date: 2023-04-02 17:39+0200\n"
+"Last-Translator: Remus-Gabriel Chelu <remusgabriel.ch...@disroot.org>\n"
+"Language-Team: Romanian <debian-l10n-roman...@lists.debian.org>\n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n==0 || (n!=1 && n%100>=1 && "
+"n%100<=19) ? 1 : 2);\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
+"X-Generator: Poedit 3.2.2\n"
+
+#: src/ufw:74
+msgid ": Need at least python 2.6)\n"
+msgstr ": Are nevoie de cel puțin python 2.6)\n"
+
+#: src/ufw:139 src/frontend.py:625 src/frontend.py:927
+msgid "Aborted"
+msgstr "Operația a fost anulată!"
+
+#: src/backend.py:70
+msgid "Couldn't determine iptables version"
+msgstr "Nu s-a putut determina versiunea «iptables»"
+
+#: src/backend.py:149
+msgid "problem running sysctl"
+msgstr "problemă la rularea «sysctl»"
+
+#: src/backend.py:188
+msgid "Checks disabled"
+msgstr "Verificări dezactivate"
+
+#: src/backend.py:194
+msgid "ERROR: this script should not be SUID"
+msgstr "EROARE: acest script nu ar trebui să aibă bitul SUID activat"
+
+#: src/backend.py:197
+msgid "ERROR: this script should not be SGID"
+msgstr "EROARE: acest script nu ar trebui să aibă bitul SGID activat"
+
+#: src/backend.py:202
+msgid "You need to be root to run this script"
+msgstr "Trebuie să fiți „root” pentru a rula acest script"
+
+#: src/backend.py:212
+#, python-format
+msgid "'%s' does not exist"
+msgstr "„%s” nu există"
+
+#: src/backend.py:235 src/backend_iptables.py:1416
+#, python-format
+msgid "Couldn't stat '%s'"
+msgstr "Nu s-a putut stabili starea lui „%s”"
+
+#: src/backend.py:253
+#, python-format
+msgid "uid is %(uid)s but '%(path)s' is owned by %(st_uid)s"
+msgstr "uid este %(uid)s, dar „%(path)s” este deținut de %(st_uid)s"
+
+#: src/backend.py:260
+#, python-format
+msgid "%s is world writable!"
+msgstr "%s are permisiuni de scriere pentru toți utilizatorii!"
+
+#: src/backend.py:265
+#, python-format
+msgid "%s is group writable!"
+msgstr "%s are permisiuni de scriere pentru toți membrii grupului!"
+
+#: src/backend.py:281
+#, python-format
+msgid "'%(f)s' file '%(name)s' does not exist"
+msgstr "„%(f)s” fișierul „%(name)s” nu există"
+
+#: src/backend.py:292 src/backend_iptables.py:690
+#, python-format
+msgid "Couldn't open '%s' for reading"
+msgstr "Nu s-a putut deschide „%s” pentru citire"
+
+#: src/backend.py:306
+#, python-format
+msgid "Missing policy for '%s'"
+msgstr "Lipsește politica pentru „%s”"
+
+#: src/backend.py:310
+#, python-format
+msgid "Invalid policy '%(policy)s' for '%(chain)s'"
+msgstr "Politica „%(policy)s” nu este validă pentru „%(chain)s”"
+
+#: src/backend.py:317
+msgid "Invalid option"
+msgstr "Opțiune nevalidă"
+
+#: src/backend.py:323 src/backend_iptables.py:790
+#, python-format
+msgid "'%s' is not writable"
+msgstr "„%s” nu poate fi scris"
+
+#: src/backend.py:370 src/backend_iptables.py:94
+#, python-format
+msgid "Unsupported policy '%s'"
+msgstr "Politica „%s” nu este acceptată"
+
+#: src/backend.py:373
+#, python-format
+msgid "Default application policy changed to '%s'"
+msgstr "Politica implicită de aplicație s-a schimbat în „%s”"
+
+#: src/backend.py:440
+msgid "No rules found for application profile"
+msgstr "Nu s-au găsit reguli pentru profilul aplicației"
+
+#: src/backend.py:496
+#, python-format
+msgid "Rules updated for profile '%s'"
+msgstr "S-au actualizat regulile pentru profilul „%s”"
+
+#: src/backend.py:502
+msgid "Couldn't update application rules"
+msgstr "Nu s-au putut actualiza regulile aplicației"
+
+#: src/backend.py:524
+#, python-format
+msgid "Found multiple matches for '%s'. Please use exact profile name"
+msgstr ""
+"S-au găsit mai multe potriviri pentru „%s”. Trebuie să utilizați numele exact 
"
+"al profilului"
+
+#: src/backend.py:527
+#, python-format
+msgid "Could not find a profile matching '%s'"
+msgstr "Nu s-a putut găsi un profil care să se potrivească cu „%s”"
+
+#: src/backend.py:594
+msgid "Logging: "
+msgstr "Jurnalizare: "
+
+#: src/backend.py:598
+msgid "unknown"
+msgstr "necunoscut"
+
+#: src/backend.py:610 src/backend_iptables.py:1284
+#, python-format
+msgid "Invalid log level '%s'"
+msgstr "Nivel de jurnalizare nevalid „%s”"
+
+#: src/backend.py:625
+msgid "Logging disabled"
+msgstr "Jurnalizare dezactivată"
+
+#: src/backend.py:627
+msgid "Logging enabled"
+msgstr "Jurnalizare activată"
+
+#: src/common.py:196
+#, python-format
+msgid "Bad port '%s'"
+msgstr "Port incorect „%s”"
+
+#: src/common.py:252
+#, python-format
+msgid "Unsupported protocol '%s'"
+msgstr "Protocol neacceptat „%s”"
+
+#: src/common.py:280
+msgid "Bad source address"
+msgstr "Adresă sursă greșită"
+
+#: src/common.py:290
+msgid "Bad destination address"
+msgstr "Adresă de destinație greșită"
+
+#: src/common.py:309
+msgid "Bad interface type"
+msgstr "Tip de interfață greșit"
+
+#: src/common.py:314
+msgid "Bad interface name: reserved character: '!'"
+msgstr "Nume de interfață greșit: caracter rezervat: '!'"
+
+#: src/common.py:318
+msgid "Bad interface name: can't use interface aliases"
+msgstr "Nume de interfață greșit: nu se pot folosi alias de interfață"
+
+#: src/common.py:322
+msgid "Bad interface name: can't use '.' or '..'"
+msgstr "Nume de interfață greșit: nu se poate folosi „.” sau „..”"
+
+#: src/common.py:326
+msgid "Bad interface name: interface name is empty"
+msgstr "Nume de interfață greșit: numele interfeței este gol"
+
+#: src/common.py:330
+msgid "Bad interface name: interface name too long"
+msgstr "Nume de interfață greșit: numele interfeței este prea lung"
+
+#: src/common.py:335
+msgid "Bad interface name"
+msgstr "Nume de interfață greșit"
+
+#: src/common.py:349
+#, python-format
+msgid "Insert position '%s' is not a valid position"
+msgstr "Poziția de inserare „%s” nu este o poziție validă"
+
+#: src/common.py:359
+#, python-format
+msgid "Invalid log type '%s'"
+msgstr "Tip de jurnalizare nevalid „%s”"
+
+#: src/common.py:367
+#, python-format
+msgid "Unsupported direction '%s'"
+msgstr "Direcția „%s” nu este acceptată"
+
+#: src/common.py:386
+msgid "Could not normalize source address"
+msgstr "Nu s-a putut normaliza adresa sursă"
+
+#: src/common.py:397
+msgid "Could not normalize destination address"
+msgstr "Nu s-a putut normaliza adresa de destinație"
+
+#: src/common.py:463
+msgid "Found exact match"
+msgstr "S-a găsit potrivirea exactă"
+
+#: src/common.py:468
+msgid "Found exact match, excepting comment"
+msgstr "S-a găsit potrivire exactă, cu excepția comentariului"
+
+#: src/common.py:472
+#, python-format
+msgid ""
+"Found non-action/non-logtype/comment match (%(xa)s/%(ya)s/'%(xc)s' %(xl)s/"
+"%(yl)s/'%(yc)s')"
+msgstr ""
+"S-a găsit potrivirea „non-action/non-logtype/comment”: 
(%(xa)s/%(ya)s/'%(xc)s' "
+"%(xl)s/%(yl)s/'%(yc)s'"
+
+#: src/common.py:630
+#, python-format
+msgid "Improper rule syntax ('%s' specified with app rule)"
+msgstr "Sintaxă incorectă a regulii („%s” specificată cu regula aplicației)"
+
+#: src/common.py:637
+#, python-format
+msgid "Invalid IPv6 address with protocol '%s'"
+msgstr "Adresă IPv6 nevalidă cu protocolul „%s”"
+
+#: src/common.py:643 src/util.py:84
+#, python-format
+msgid "Invalid port with protocol '%s'"
+msgstr "Port nevalid cu protocolul „%s”"
+
+#: src/parser.py:110
+#, python-format
+msgid "Cannot insert rule at position '%s'"
+msgstr "Nu se poate insera regula la poziția „%s”"
+
+#: src/parser.py:148
+msgid "Invalid interface clause"
+msgstr "Clauza de interfață nu este validă"
+
+#: src/parser.py:174
+msgid "Option 'log' not allowed here"
+msgstr "Opțiunea „log” nu este permisă aici"
+
+#: src/parser.py:178
+msgid "Option 'log-all' not allowed here"
+msgstr "Opțiunea „log-all” nu este permisă aici"
+
+#: src/parser.py:185
+msgid "Option 'comment' missing required argument"
+msgstr "Opțiunii „comment” îi lipsește argumentul necesar"
+
+#: src/parser.py:191
+msgid "Comment may not contain \"'\""
+msgstr "Comentariul nu poate conține „’”"
+
+#: src/parser.py:233 src/parser.py:359
+msgid "Port ranges must be numeric"
+msgstr "Intervalele de porturi trebuie să fie numerice"
+
+#: src/parser.py:242 src/util.py:87
+msgid "Bad port"
+msgstr "Port incorect"
+
+#: src/parser.py:245
+msgid "Wrong number of arguments"
+msgstr "Număr greșit de argumente"
+
+#: src/parser.py:249
+msgid "Need 'to' or 'from' clause"
+msgstr "Se necesită clauza „to” sau „from”"
+
+#: src/parser.py:264
+msgid "Improper rule syntax"
+msgstr "Sintaxă incorectă a regulii"
+
+#: src/parser.py:271
+#, python-format
+msgid "Invalid token '%s'"
+msgstr "Indicativ (token) nevalid „%s”"
+
+#: src/parser.py:283
+msgid "Invalid 'proto' clause"
+msgstr "Clauza „proto” nu este validă"
+
+#: src/parser.py:298
+#, python-format
+msgid "Invalid '%s' clause"
+msgstr "Clauza „%s” nu este validă"
+
+#: src/parser.py:320
+msgid "Invalid 'from' clause"
+msgstr "Clauza „from” nu este validă"
+
+#: src/parser.py:342
+msgid "Invalid 'to' clause"
+msgstr "Clauza „to” nu este validă"
+
+#: src/parser.py:347
+#, python-format
+msgid "Need 'from' or 'to' with '%s'"
+msgstr "Este nevoie de „from” sau „to” cu „%s”"
+
+#: src/parser.py:374
+msgid "Invalid 'port' clause"
+msgstr "Clauza „port” nu este validă"
+
+#: src/parser.py:383
+msgid "Mixed IP versions for 'from' and 'to'"
+msgstr "Versiuni IP amestecate pentru „from” și „to”"
+
+#: src/parser.py:400 src/parser.py:410 src/parser.py:419
+msgid "Could not find protocol"
+msgstr "Nu s-a putut găsi protocolul"
+
+#: src/parser.py:426
+msgid "Protocol mismatch (from/to)"
+msgstr "Nepotrivire protocol (from/to)"
+
+#: src/parser.py:433
+#, python-format
+msgid "Protocol mismatch with specified protocol %s"
+msgstr "Nepotrivire a protocolului cu protocolul specificat %s"
+
+#: src/parser.py:552
+msgid "'route delete NUM' unsupported. Use 'delete NUM' instead."
+msgstr ""
+"directiva „route delete NUM” nu este acceptată. Folosiți „delete NUM” în 
schimb."
+
+#: src/parser.py:585
+msgid "Invalid interface clause for route rule"
+msgstr "Clauza de interfață nu este validă pentru regula de rută"
+
+#: src/parser.py:884
+#, python-format
+msgid "Command '%s' already exists"
+msgstr "Comanda „%s” există deja"
+
+#: src/util.py:446
+msgid "Couldn't find pid (is /proc mounted?)"
+msgstr "Nu s-a putut găsi identificatorul de proces (pid); este „/proc” 
montat?"
+
+#: src/util.py:450
+#, python-format
+msgid "Couldn't find parent pid for '%s'"
+msgstr "Nu s-a putut găsi identificatorul procesului părinte (ppid) pentru 
„%s”"
+
+#: src/util.py:460
+#, python-format
+msgid "Couldn't find '%s'"
+msgstr "Nu s-a putut găsi „%s”"
+
+#: src/util.py:466
+#, python-format
+msgid "Could not find executable for '%s'"
+msgstr "Nu s-a putut găsi executabilul pentru „%s”"
+
+#: src/util.py:1026
+#, python-format
+msgid "Could not get statistics for '%s'"
+msgstr "Nu s-au putut obține statisticile pentru „%s”"
+
+#: src/backend_iptables.py:78
+msgid "New profiles:"
+msgstr "Profiluri noi:"
+
+#: src/backend_iptables.py:99
+#, python-format
+msgid "Unsupported policy for direction '%s'"
+msgstr "Politică neacceptată pentru direcția „%s”"
+
+#: src/backend_iptables.py:159
+#, python-format
+msgid "Default %(direction)s policy changed to '%(policy)s'\n"
+msgstr "Politica implicită %(direction)s a fost schimbată în „%(policy)s”\n"
+
+#: src/backend_iptables.py:161
+msgid "(be sure to update your rules accordingly)"
+msgstr "(asigurați-vă că vă actualizați regulile în consecință)"
+
+#: src/backend_iptables.py:168
+msgid "Checking raw iptables\n"
+msgstr "Se verifică „iptables” brute\n"
+
+#: src/backend_iptables.py:169
+msgid "Checking raw ip6tables\n"
+msgstr "Se verifică „ip6tables” brute\n"
+
+#: src/backend_iptables.py:262
+msgid "Checking iptables\n"
+msgstr "Se verifică „iptables”\n"
+
+#: src/backend_iptables.py:264
+msgid "Checking ip6tables\n"
+msgstr "Se verifică „ip6tables”\n"
+
+#: src/backend_iptables.py:267 src/backend_iptables.py:568
+msgid "problem running"
+msgstr "problemă rulând"
+
+#: src/backend_iptables.py:273
+msgid "Status: inactive"
+msgstr "Stare: inactiv"
+
+#: src/backend_iptables.py:443
+msgid "To"
+msgstr "La"
+
+#: src/backend_iptables.py:444
+msgid "From"
+msgstr "De la"
+
+#: src/backend_iptables.py:445
+msgid "Action"
+msgstr "Acțiune"
+
+#: src/backend_iptables.py:461 src/backend_iptables.py:465
+msgid "\n"
+msgstr "\n"
+
+#: src/backend_iptables.py:473
+#, python-format
+msgid "Default: %(in)s (incoming), %(out)s (outgoing), %(routed)s (routed)"
+msgstr ""
+"Implicit: %(in)s (care-intră), %(out)s (care-iese), %(routed)s (direcționat)"
+
+#: src/backend_iptables.py:481
+#, python-format
+msgid ""
+"Status: active\n"
+"%(log)s\n"
+"%(pol)s\n"
+"%(app)s%(status)s"
+msgstr ""
+"Stare: activ\n"
+"%(log)s\n"
+"%(pol)s\n"
+"%(app)s%(status)s"
+
+#: src/backend_iptables.py:485
+#, python-format
+msgid "Status: active%s"
+msgstr "Stare: activ%s"
+
+#: src/backend_iptables.py:490 src/backend_iptables.py:508
+msgid "running ufw-init"
+msgstr "rulează ufw-init"
+
+#: src/backend_iptables.py:502 src/backend_iptables.py:520
+#, python-format
+msgid ""
+"problem running ufw-init\n"
+"%s"
+msgstr ""
+"problemă la rularea ufw-init\n"
+"%s"
+
+#: src/backend_iptables.py:529
+msgid "Could not set LOGLEVEL"
+msgstr "Nu s-a putut fixa LOGLEVEL"
+
+#: src/backend_iptables.py:535
+msgid "Could not load logging rules"
+msgstr "Nu s-au putut încărca regulile de înregistrare în jurnal"
+
+# R-GC, scrie:
+# aici e vorba de „invenția” w3c/americană, de-a
+# numii o terminație/sufix de cantitate multiplă sau multiplexare cu un cuvînt 
nou, care în esență
+# vrea să spună: n-uplet, adică: duplet, triplet, etc
+# ******
+# iar aici, pare să fie vorba de tripletul adresei IP a
+# unei interfețe:
+# XXXX . YYY . ZZZ
+#: src/backend_iptables.py:709
+#, python-format
+msgid "Skipping malformed tuple (bad length): %s"
+msgstr "Se omite n-uplul (tuple) malformat (lungime greșită): %s"
+
+#: src/backend_iptables.py:720
+#, python-format
+msgid "Skipping malformed tuple (iface): %s"
+msgstr "Se omite n-uplul (tuple) malformat (iface): %s"
+
+#: src/backend_iptables.py:768
+#, python-format
+msgid "Skipping malformed tuple: %s"
+msgstr "Se omite n-uplul (tuple) malformat: %s"
+
+#: src/backend_iptables.py:966
+msgid "Adding IPv6 rule failed: IPv6 not enabled"
+msgstr "Adăugarea regulii IPv6 nu a reușit: IPv6 nu este activat"
+
+#: src/backend_iptables.py:970
+#, python-format
+msgid "Skipping unsupported IPv6 '%s' rule"
+msgstr "Se omite regula IPv6 „%s” neacceptată"
+
+#: src/backend_iptables.py:974
+#, python-format
+msgid "Skipping unsupported IPv4 '%s' rule"
+msgstr "Se omite regula IPv4 „%s” neacceptată"
+
+#: src/backend_iptables.py:977
+msgid "Must specify 'tcp' or 'udp' with multiple ports"
+msgstr "Trebuie să specificați „tcp” sau „udp” cu porturi multiple"
+
+#: src/backend_iptables.py:989
+msgid "Skipping IPv6 application rule. Need at least iptables 1.4"
+msgstr ""
+"Se omite regula IPv6 a aplicației. Se necesită cel puțin versiunea iptables 
1.4"
+
+#: src/backend_iptables.py:994
+#, python-format
+msgid "Invalid position '%d'"
+msgstr "Poziție nevalidă „%d”"
+
+#: src/backend_iptables.py:998
+msgid "Cannot specify insert and delete"
+msgstr "Nu se pot specifica în același timp directivele „insert” și „delete”"
+
+#: src/backend_iptables.py:1001
+#, python-format
+msgid "Cannot insert rule at position '%d'"
+msgstr "Nu se poate insera regula la poziția „%d”"
+
+#: src/backend_iptables.py:1062
+msgid "Skipping inserting existing rule"
+msgstr "Se omite inserarea regulii existente"
+
+#: src/backend_iptables.py:1073 src/frontend.py:415
+msgid "Could not delete non-existent rule"
+msgstr "Nu s-a putut șterge regula inexistentă"
+
+#: src/backend_iptables.py:1078
+msgid "Skipping adding existing rule"
+msgstr "Se omite adăugarea unei reguli existente"
+
+#: src/backend_iptables.py:1094
+msgid "Couldn't update rules file"
+msgstr "Nu s-a putut actualiza fișierul cu reguli"
+
+#: src/backend_iptables.py:1099
+msgid "Rules updated"
+msgstr "Regulile au fost actualizate"
+
+#: src/backend_iptables.py:1101
+msgid "Rules updated (v6)"
+msgstr "Regulile au fost actualizate (v6)"
+
+#: src/backend_iptables.py:1109
+msgid "Rule inserted"
+msgstr "Regula a fost inserată"
+
+#: src/backend_iptables.py:1111
+msgid "Rule updated"
+msgstr "Regula a fost actualizată"
+
+#: src/backend_iptables.py:1121
+msgid " (skipped reloading firewall)"
+msgstr " (se omite reîncărcarea paravanului de protecție)"
+
+#: src/backend_iptables.py:1124
+msgid "Rule deleted"
+msgstr "Regula a fost ștearsă"
+
+#: src/backend_iptables.py:1127
+msgid "Rule added"
+msgstr "Regula a fost adăugată"
+
+#: src/backend_iptables.py:1144 src/backend_iptables.py:1235
+msgid "Could not update running firewall"
+msgstr "Nu s-a putut actualiza paravanul de protecție activ"
+
+#: src/backend_iptables.py:1199
+#, python-format
+msgid "Could not perform '%s'"
+msgstr "Nu s-a putut efectua „%s”"
+
+#: src/backend_iptables.py:1226
+msgid "Couldn't update rules file for logging"
+msgstr "Nu s-a putut actualiza fișierul cu reguli pentru înregistrarea în 
jurnal"
+
+#: src/backend_iptables.py:1382
+#, python-format
+msgid "Could not find '%s'. Aborting"
+msgstr "Nu s-a putut găsi „%s”. Se abandonează"
+
+#: src/backend_iptables.py:1394
+#, python-format
+msgid "'%s' already exists. Aborting"
+msgstr "„%s” există deja. Se abandonează"
+
+#: src/backend_iptables.py:1400
+#, python-format
+msgid "Backing up '%(old)s' to '%(new)s'\n"
+msgstr "Se fac copii de rezervă pentru „%(old)s” în „%(new)s”\n"
+
+#: src/backend_iptables.py:1421
+#, python-format
+msgid "WARN: '%s' is world writable"
+msgstr "AVERTISMENT: „%s” poate fi scris de toți utilizatorii"
+
+#: src/backend_iptables.py:1423
+#, python-format
+msgid "WARN: '%s' is world readable"
+msgstr "AVERTISMENT: „%s” poate fi citit de toți utilizatorii"
+
+#: src/frontend.py:93
+#, python-format
+msgid ""
+"\n"
+"Usage: %(progname)s %(command)s\n"
+"\n"
+"%(commands)s:\n"
+" %(enable)-31s enables the firewall\n"
+" %(disable)-31s disables the firewall\n"
+" %(default)-31s set default policy\n"
+" %(logging)-31s set logging to %(level)s\n"
+" %(allow)-31s add allow %(rule)s\n"
+" %(deny)-31s add deny %(rule)s\n"
+" %(reject)-31s add reject %(rule)s\n"
+" %(limit)-31s add limit %(rule)s\n"
+" %(delete)-31s delete %(urule)s\n"
+" %(insert)-31s insert %(urule)s at %(number)s\n"
+" %(route)-31s add route %(urule)s\n"
+" %(route-delete)-31s delete route %(urule)s\n"
+" %(route-insert)-31s insert route %(urule)s at %(number)s\n"
+" %(reload)-31s reload firewall\n"
+" %(reset)-31s reset firewall\n"
+" %(status)-31s show firewall status\n"
+" %(statusnum)-31s show firewall status as numbered list of %(rules)s\n"
+" %(statusverbose)-31s show verbose firewall status\n"
+" %(show)-31s show firewall report\n"
+" %(version)-31s display version information\n"
+"\n"
+"%(appcommands)s:\n"
+" %(applist)-31s list application profiles\n"
+" %(appinfo)-31s show information on %(profile)s\n"
+" %(appupdate)-31s update %(profile)s\n"
+" %(appdefault)-31s set default application policy\n"
+msgstr ""
+"\n"
+"Utilizare: %(progname)s %(command)s\n"
+"\n"
+"%(commands)s:\n"
+" %(enable)-31s activează paravanul de protecție\n"
+" %(disable)-31s dezactivează paravanul de protecție\n"
+" %(default)-31s stabilește politica implicită\n"
+" %(logging)-31s stabilește nivelul jurnalizării la %(level)sn\n"
+" %(allow)-31s adaugă %(rule)s « permite»\n"
+" %(deny)-31s adaugă %(rule)s « refuză»\n"
+" %(reject)-31s adaugă %(rule)s « respinge»\n"
+" %(limit)-31s adaugă %(rule)s «limitei»\n"
+" %(delete)-31s șterge %(urule)s\n"
+" %(insert)-31s inserează %(urule)s la %(number)s\n"
+" %(route)-31s adaugă %(rule)s «direcționare»\n"
+" %(route-delete)-31s șterge %(rule)s «direcționare»\n"
+" %(route-insert)-31s inserează %(rule)s «direcționare» la %(number)s\n"
+" %(reload)-31s reîncarcă paravanul de protecție\n"
+" %(reset)-31s reinițiază paravanul de protecție\n"
+" %(status)-31s afișează starea paravanului de protecție\n"
+" %(statusnum)-31s afișează starea paravanului de protecție ca listă 
numerotată "
+"de %(rules)s\n"
+" %(statusverbose)-31s afișează starea paravanului de protecție cu informații "
+"detaliate\n"
+" %(show)-31s afișează raportul paravanului de protecție\n"
+" %(version)-31s afișează informațiile despre versiune\n"
+"\n"
+"%(appcommands)s:\n"
+" %(applist)-31s listează profilurile aplicațiilor\n"
+" %(appinfo)-31s afișează informații despre %(profile)s\n"
+" %(appupdate)-31s actualizează %(profile)s\n"
+" %(appdefault)-31s stabilește politica implicită de aplicație\n"
+
+#: src/frontend.py:176
+msgid "n"
+msgstr "n"
+
+#: src/frontend.py:177
+msgid "y"
+msgstr "d"
+
+#: src/frontend.py:178
+msgid "yes"
+msgstr "da"
+
+#: src/frontend.py:223
+msgid "Firewall is active and enabled on system startup"
+msgstr ""
+"Paravanul de protecție este activ și activat pentru lansare la pornirea "
+"sistemului"
+
+#: src/frontend.py:230
+msgid "Firewall stopped and disabled on system startup"
+msgstr ""
+"Paravanul de protecție este oprit și dezactivat pentru lansare la pornirea "
+"sistemului"
+
+#: src/frontend.py:282
+msgid "Could not get listening status"
+msgstr "Nu s-a putut obține starea de ascultare"
+
+#: src/frontend.py:351
+msgid "Added user rules (see 'ufw status' for running firewall):"
+msgstr ""
+"S-au adăugat regulile date de utilizator (consultați „ufw status” pentru a "
+"cunoaște starea actuală a paravanului de protecție):"
+
+# R-GC, scrie:
+# bănuiesc că e vorba de «reguli sau interfețe»,
+# nu văd nimic de genul masculin relaționat cu
+# un paravan de protecție (decît, bineînțeles, el însuși) :)
+#: src/frontend.py:354
+msgid ""
+"\n"
+"(None)"
+msgstr ""
+"\n"
+"(Niciuna)"
+
+#: src/frontend.py:410 src/frontend.py:521 src/frontend.py:534
+#, python-format
+msgid "Invalid IP version '%s'"
+msgstr "Versiunea IP „%s” nu este validă"
+
+#: src/frontend.py:441
+msgid "Invalid position '"
+msgstr "Poziție nevalidă '"
+
+#: src/frontend.py:531
+msgid "IPv6 support not enabled"
+msgstr "Suportul pentru protocolul IPv6 nu este activat"
+
+#: src/frontend.py:542
+msgid "Rule changed after normalization"
+msgstr "Regulă modificată după normalizare"
+
+#: src/frontend.py:566
+#, python-format
+msgid "Could not back out rule '%s'"
+msgstr "Nu s-a putut restabilii definiția anterioară a regulei „%s”"
+
+#: src/frontend.py:570
+msgid ""
+"\n"
+"Error applying application rules."
+msgstr ""
+"\n"
+"Eroare la aplicarea regulilor aplicației."
+
+#: src/frontend.py:572
+msgid " Some rules could not be unapplied."
+msgstr " Unele reguli nu au putut fi anulate."
+
+#: src/frontend.py:574
+msgid " Attempted rules successfully unapplied."
+msgstr " Regulile încercate au fost anulate cu succes."
+
+#: src/frontend.py:585
+#, python-format
+msgid "Could not find rule '%s'"
+msgstr "Nu s-a putut găsi regula „%s”"
+
+#: src/frontend.py:590 src/frontend.py:595
+#, python-format
+msgid "Could not find rule '%d'"
+msgstr "Nu s-a putut găsi regula „%d”"
+
+#: src/frontend.py:611
+#, python-format
+msgid ""
+"Deleting:\n"
+" %(rule)s\n"
+"Proceed with operation (%(yes)s|%(no)s)? "
+msgstr ""
+"Se șterge:\n"
+"  %(rule)s\n"
+"Continuați cu operația (%(yes)s|%(no)s)? "
+
+#: src/frontend.py:643
+msgid "Unsupported default policy"
+msgstr "Politică implicită neacceptată"
+
+#: src/frontend.py:672 src/frontend.py:817
+msgid "Firewall reloaded"
+msgstr "Paravanul de protecție a fost reîncărcat"
+
+#: src/frontend.py:674
+msgid "Firewall not enabled (skipping reload)"
+msgstr "Paravanul de protecție nu este activat (se omite reîncărcarea)"
+
+#: src/frontend.py:691 src/frontend.py:705 src/frontend.py:742
+msgid "Invalid profile name"
+msgstr "Nume de profil nevalid"
+
+#: src/frontend.py:710 src/frontend.py:892
+#, python-format
+msgid "Unsupported action '%s'"
+msgstr "Acțiune neacceptată „%s”"
+
+#: src/frontend.py:729
+msgid "Available applications:"
+msgstr "Aplicații disponibile:"
+
+#: src/frontend.py:750
+#, python-format
+msgid "Could not find profile '%s'"
+msgstr "Nu s-a putut găsi profilul „%s”"
+
+#: src/frontend.py:755
+msgid "Invalid profile"
+msgstr "Profil nevalid"
+
+#: src/frontend.py:758
+#, python-format
+msgid "Profile: %s\n"
+msgstr "Profil: %s\n"
+
+#: src/frontend.py:759
+#, python-format
+msgid "Title: %s\n"
+msgstr "Titlu: %s\n"
+
+#: src/frontend.py:762
+#, python-format
+msgid ""
+"Description: %s\n"
+"\n"
+msgstr ""
+"Descriere: %s\n"
+"\n"
+
+#: src/frontend.py:768
+msgid "Ports:"
+msgstr "Porturi:"
+
+#: src/frontend.py:770
+msgid "Port:"
+msgstr "Port:"
+
+#: src/frontend.py:819
+msgid "Skipped reloading firewall"
+msgstr "S-a omis reîncărcarea paravanului de protecție"
+
+#: src/frontend.py:829
+msgid "Cannot specify 'all' with '--add-new'"
+msgstr "Nu se pot specifica „all” (toate regulile) cu „--add-new”"
+
+#: src/frontend.py:844
+#, python-format
+msgid "Unknown policy '%s'"
+msgstr "Politică necunoscută „%s”"
+
+#: src/frontend.py:901
+#, python-format
+msgid ""
+"Command may disrupt existing ssh connections. Proceed with operation 
(%(yes)s|"
+"%(no)s)? "
+msgstr ""
+"Comanda poate întrerupe conexiunile SSH existente. Continuați cu operația "
+"(%(yes)s|%(no)s)? "
+
+#: src/frontend.py:914
+#, python-format
+msgid ""
+"Resetting all rules to installed defaults. Proceed with operation (%(yes)s|"
+"%(no)s)? "
+msgstr ""
+"Se restabilesc toate regulile la valorile implicite instalate. Continuați cu "
+"operația (%(yes)s|%(no)s)? "
+
+#: src/frontend.py:918
+#, python-format
+msgid ""
+"Resetting all rules to installed defaults. This may disrupt existing ssh "
+"connections. Proceed with operation (%(yes)s|%(no)s)? "
+msgstr ""
+"Se restabilesc toate regulile la valorile implicite instalate. Acest lucru "
+"poate întrerupe conexiunile SSH existente. Continuați cu operația (%(yes)s|"
+"%(no)s)? "
+
+#: src/applications.py:37
+msgid "Profiles directory does not exist"
+msgstr "Directorul de profiluri nu există"
+
+#: src/applications.py:69
+#, python-format
+msgid "Skipping '%s': couldn't stat"
+msgstr "Se omite „%s”: nu se poate obține starea"
+
+#: src/applications.py:74
+#, python-format
+msgid "Skipping '%s': too big"
+msgstr "Se omite „%s”: este prea mare"
+
+#: src/applications.py:79
+#, python-format
+msgid "Skipping '%s': too many files read already"
+msgstr "Se omite „%s”: prea multe fișiere citite deja"
+
+#: src/applications.py:93
+#, python-format
+msgid "Skipping '%s': couldn't process"
+msgstr "Se omite „%s”: nu s-a putut procesa"
+
+#: src/applications.py:100
+#, python-format
+msgid "Skipping '%s': name too long"
+msgstr "Se omite „%s”: numele este prea lung"
+
+#: src/applications.py:105
+#, python-format
+msgid "Skipping '%s': invalid name"
+msgstr "Se omite „%s”: numele nu este valid"
+
+#: src/applications.py:111
+#, python-format
+msgid "Skipping '%s': also in /etc/services"
+msgstr "Se omite „%s”: de asemenea, în „/etc/services”"
+
+#: src/applications.py:120
+#, python-format
+msgid "Skipping '%s': field too long"
+msgstr "Se omite „%s”: câmpul este prea lung"
+
+#: src/applications.py:125
+#, python-format
+msgid "Skipping '%(value)s': value too long for '%(field)s'"
+msgstr "Se omite „%(value)s”: valoarea este prea X pentru „%(field)s”"
+
+#: src/applications.py:135
+#, python-format
+msgid "Duplicate profile '%s', using last found"
+msgstr "Profil duplicat „%s”, se folosește ultimul găsit"
+
+#: src/applications.py:178
+#, python-format
+msgid "Profile '%(fn)s' missing required field '%(f)s'"
+msgstr "Din profilul „%(fn)s” lipsește câmpul obligatoriu „%(f)s”"
+
+#: src/applications.py:183
+#, python-format
+msgid "Profile '%(fn)s' has empty required field '%(f)s'"
+msgstr "Profilul „%(fn)s” are câmpul obligatoriu gol „%(f)s”"
+
+#: src/applications.py:198
+#, python-format
+msgid "Invalid ports in profile '%s'"
+msgstr "Porturi nevalide în profilul „%s”"
diff -Nru ufw-0.36.1/locales/po/ufw.pot ufw-0.36.2/locales/po/ufw.pot
--- ufw-0.36.1/locales/po/ufw.pot       2021-09-18 20:19:01.000000000 -0500
+++ ufw-0.36.2/locales/po/ufw.pot       2023-05-18 08:07:56.000000000 -0500
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-12-14 10:02-0600\n"
+"POT-Creation-Date: 2023-05-18 08:07-0500\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <l...@li.org>\n"
@@ -21,601 +21,535 @@
 msgid ": Need at least python 2.6)\n"
 msgstr ""
 
-#: src/ufw:139 src/frontend.py:625 src/frontend.py:927
+#: src/ufw:139 src/frontend.py:636 src/frontend.py:938
 msgid "Aborted"
 msgstr ""
 
-#: src/backend.py:70
-msgid "Couldn't determine iptables version"
-msgstr ""
-
-#: src/backend.py:149
-msgid "problem running sysctl"
-msgstr ""
-
-#: src/backend.py:188
-msgid "Checks disabled"
-msgstr ""
-
-#: src/backend.py:194
-msgid "ERROR: this script should not be SUID"
-msgstr ""
-
-#: src/backend.py:197
-msgid "ERROR: this script should not be SGID"
-msgstr ""
-
-#: src/backend.py:202
-msgid "You need to be root to run this script"
+#: src/applications.py:37
+msgid "Profiles directory does not exist"
 msgstr ""
 
-#: src/backend.py:212
+#: src/applications.py:69
 #, python-format
-msgid "'%s' does not exist"
+msgid "Skipping '%s': couldn't stat"
 msgstr ""
 
-#: src/backend.py:235 src/backend_iptables.py:1416
+#: src/applications.py:74
 #, python-format
-msgid "Couldn't stat '%s'"
+msgid "Skipping '%s': too big"
 msgstr ""
 
-#: src/backend.py:253
+#: src/applications.py:79
 #, python-format
-msgid "uid is %(uid)s but '%(path)s' is owned by %(st_uid)s"
+msgid "Skipping '%s': too many files read already"
 msgstr ""
 
-#: src/backend.py:260
+#: src/applications.py:93
 #, python-format
-msgid "%s is world writable!"
+msgid "Skipping '%s': couldn't process"
 msgstr ""
 
-#: src/backend.py:265
+#: src/applications.py:100
 #, python-format
-msgid "%s is group writable!"
+msgid "Skipping '%s': name too long"
 msgstr ""
 
-#: src/backend.py:281
+#: src/applications.py:105
 #, python-format
-msgid "'%(f)s' file '%(name)s' does not exist"
+msgid "Skipping '%s': invalid name"
 msgstr ""
 
-#: src/backend.py:292 src/backend_iptables.py:690
+#: src/applications.py:111
 #, python-format
-msgid "Couldn't open '%s' for reading"
+msgid "Skipping '%s': also in /etc/services"
 msgstr ""
 
-#: src/backend.py:306
+#: src/applications.py:120
 #, python-format
-msgid "Missing policy for '%s'"
+msgid "Skipping '%s': field too long"
 msgstr ""
 
-#: src/backend.py:310
+#: src/applications.py:125
 #, python-format
-msgid "Invalid policy '%(policy)s' for '%(chain)s'"
-msgstr ""
-
-#: src/backend.py:317
-msgid "Invalid option"
+msgid "Skipping '%(value)s': value too long for '%(field)s'"
 msgstr ""
 
-#: src/backend.py:323 src/backend_iptables.py:790
+#: src/applications.py:135
 #, python-format
-msgid "'%s' is not writable"
+msgid "Duplicate profile '%s', using last found"
 msgstr ""
 
-#: src/backend.py:370 src/backend_iptables.py:94
+#: src/applications.py:178
 #, python-format
-msgid "Unsupported policy '%s'"
+msgid "Profile '%(fn)s' missing required field '%(f)s'"
 msgstr ""
 
-#: src/backend.py:373
+#: src/applications.py:183
 #, python-format
-msgid "Default application policy changed to '%s'"
-msgstr ""
-
-#: src/backend.py:440
-msgid "No rules found for application profile"
+msgid "Profile '%(fn)s' has empty required field '%(f)s'"
 msgstr ""
 
-#: src/backend.py:496
+#: src/applications.py:198
 #, python-format
-msgid "Rules updated for profile '%s'"
+msgid "Invalid ports in profile '%s'"
 msgstr ""
 
-#: src/backend.py:502
-msgid "Couldn't update application rules"
+#: src/backend_iptables.py:82
+msgid "New profiles:"
 msgstr ""
 
-#: src/backend.py:524
+#: src/backend_iptables.py:98 src/backend.py:370
 #, python-format
-msgid "Found multiple matches for '%s'. Please use exact profile name"
+msgid "Unsupported policy '%s'"
 msgstr ""
 
-#: src/backend.py:527
+#: src/backend_iptables.py:103
 #, python-format
-msgid "Could not find a profile matching '%s'"
-msgstr ""
-
-#: src/backend.py:594
-msgid "Logging: "
-msgstr ""
-
-#: src/backend.py:598
-msgid "unknown"
+msgid "Unsupported policy for direction '%s'"
 msgstr ""
 
-#: src/backend.py:610 src/backend_iptables.py:1284
+#: src/backend_iptables.py:163
 #, python-format
-msgid "Invalid log level '%s'"
-msgstr ""
-
-#: src/backend.py:625
-msgid "Logging disabled"
-msgstr ""
-
-#: src/backend.py:627
-msgid "Logging enabled"
+msgid "Default %(direction)s policy changed to '%(policy)s'\n"
 msgstr ""
 
-#: src/common.py:196
-#, python-format
-msgid "Bad port '%s'"
+#: src/backend_iptables.py:165
+msgid "(be sure to update your rules accordingly)"
 msgstr ""
 
-#: src/common.py:252
-#, python-format
-msgid "Unsupported protocol '%s'"
+#: src/backend_iptables.py:172
+msgid "Checking raw iptables\n"
 msgstr ""
 
-#: src/common.py:280
-msgid "Bad source address"
+#: src/backend_iptables.py:173
+msgid "Checking raw ip6tables\n"
 msgstr ""
 
-#: src/common.py:290
-msgid "Bad destination address"
+#: src/backend_iptables.py:266
+msgid "Checking iptables\n"
 msgstr ""
 
-#: src/common.py:309
-msgid "Bad interface type"
+#: src/backend_iptables.py:268
+msgid "Checking ip6tables\n"
 msgstr ""
 
-#: src/common.py:314
-msgid "Bad interface name: reserved character: '!'"
+#: src/backend_iptables.py:271 src/backend_iptables.py:572
+msgid "problem running"
 msgstr ""
 
-#: src/common.py:318
-msgid "Bad interface name: can't use interface aliases"
+#: src/backend_iptables.py:277
+msgid "Status: inactive"
 msgstr ""
 
-#: src/common.py:322
-msgid "Bad interface name: can't use '.' or '..'"
+#: src/backend_iptables.py:447
+msgid "To"
 msgstr ""
 
-#: src/common.py:326
-msgid "Bad interface name: interface name is empty"
+#: src/backend_iptables.py:448
+msgid "From"
 msgstr ""
 
-#: src/common.py:330
-msgid "Bad interface name: interface name too long"
+#: src/backend_iptables.py:449
+msgid "Action"
 msgstr ""
 
-#: src/common.py:335
-msgid "Bad interface name"
+#: src/backend_iptables.py:465 src/backend_iptables.py:469
+msgid "\n"
 msgstr ""
 
-#: src/common.py:349
+#: src/backend_iptables.py:477
 #, python-format
-msgid "Insert position '%s' is not a valid position"
+msgid "Default: %(in)s (incoming), %(out)s (outgoing), %(routed)s (routed)"
 msgstr ""
 
-#: src/common.py:359
+#: src/backend_iptables.py:485
 #, python-format
-msgid "Invalid log type '%s'"
+msgid ""
+"Status: active\n"
+"%(log)s\n"
+"%(pol)s\n"
+"%(app)s%(status)s"
 msgstr ""
 
-#: src/common.py:367
+#: src/backend_iptables.py:489
 #, python-format
-msgid "Unsupported direction '%s'"
+msgid "Status: active%s"
 msgstr ""
 
-#: src/common.py:386
-msgid "Could not normalize source address"
+#: src/backend_iptables.py:494 src/backend_iptables.py:512
+msgid "running ufw-init"
 msgstr ""
 
-#: src/common.py:397
-msgid "Could not normalize destination address"
+#: src/backend_iptables.py:506 src/backend_iptables.py:524
+#, python-format
+msgid ""
+"problem running ufw-init\n"
+"%s"
 msgstr ""
 
-#: src/common.py:463
-msgid "Found exact match"
+#: src/backend_iptables.py:533
+msgid "Could not set LOGLEVEL"
 msgstr ""
 
-#: src/common.py:468
-msgid "Found exact match, excepting comment"
+#: src/backend_iptables.py:539
+msgid "Could not load logging rules"
 msgstr ""
 
-#: src/common.py:472
+#: src/backend_iptables.py:694 src/backend.py:292
 #, python-format
-msgid ""
-"Found non-action/non-logtype/comment match (%(xa)s/%(ya)s/'%(xc)s' %(xl)s/"
-"%(yl)s/'%(yc)s')"
+msgid "Couldn't open '%s' for reading"
 msgstr ""
 
-#: src/common.py:630
+#: src/backend_iptables.py:713
 #, python-format
-msgid "Improper rule syntax ('%s' specified with app rule)"
+msgid "Skipping malformed tuple (bad length): %s"
 msgstr ""
 
-#: src/common.py:637
+#: src/backend_iptables.py:724
 #, python-format
-msgid "Invalid IPv6 address with protocol '%s'"
+msgid "Skipping malformed tuple (iface): %s"
 msgstr ""
 
-#: src/common.py:643 src/util.py:84
+#: src/backend_iptables.py:772
 #, python-format
-msgid "Invalid port with protocol '%s'"
+msgid "Skipping malformed tuple: %s"
 msgstr ""
 
-#: src/parser.py:110
+#: src/backend_iptables.py:794 src/backend.py:323
 #, python-format
-msgid "Cannot insert rule at position '%s'"
-msgstr ""
-
-#: src/parser.py:148
-msgid "Invalid interface clause"
+msgid "'%s' is not writable"
 msgstr ""
 
-#: src/parser.py:174
-msgid "Option 'log' not allowed here"
+#: src/backend_iptables.py:970
+msgid "Adding IPv6 rule failed: IPv6 not enabled"
 msgstr ""
 
-#: src/parser.py:178
-msgid "Option 'log-all' not allowed here"
+#: src/backend_iptables.py:974
+#, python-format
+msgid "Skipping unsupported IPv6 '%s' rule"
 msgstr ""
 
-#: src/parser.py:185
-msgid "Option 'comment' missing required argument"
+#: src/backend_iptables.py:978
+#, python-format
+msgid "Skipping unsupported IPv4 '%s' rule"
 msgstr ""
 
-#: src/parser.py:191
-msgid "Comment may not contain \"'\""
+#: src/backend_iptables.py:981
+msgid "Must specify 'tcp' or 'udp' with multiple ports"
 msgstr ""
 
-#: src/parser.py:233 src/parser.py:359
-msgid "Port ranges must be numeric"
+#: src/backend_iptables.py:993
+msgid "Skipping IPv6 application rule. Need at least iptables 1.4"
 msgstr ""
 
-#: src/parser.py:242 src/util.py:87
-msgid "Bad port"
+#: src/backend_iptables.py:998
+#, python-format
+msgid "Invalid position '%d'"
 msgstr ""
 
-#: src/parser.py:245
-msgid "Wrong number of arguments"
+#: src/backend_iptables.py:1002
+msgid "Cannot specify insert and delete"
 msgstr ""
 
-#: src/parser.py:249
-msgid "Need 'to' or 'from' clause"
+#: src/backend_iptables.py:1063
+msgid "Skipping inserting existing rule"
 msgstr ""
 
-#: src/parser.py:264
-msgid "Improper rule syntax"
+#: src/backend_iptables.py:1074 src/frontend.py:426
+msgid "Could not delete non-existent rule"
 msgstr ""
 
-#: src/parser.py:271
-#, python-format
-msgid "Invalid token '%s'"
+#: src/backend_iptables.py:1079
+msgid "Skipping adding existing rule"
 msgstr ""
 
-#: src/parser.py:283
-msgid "Invalid 'proto' clause"
+#: src/backend_iptables.py:1095
+msgid "Couldn't update rules file"
 msgstr ""
 
-#: src/parser.py:298
-#, python-format
-msgid "Invalid '%s' clause"
+#: src/backend_iptables.py:1100
+msgid "Rules updated"
 msgstr ""
 
-#: src/parser.py:320
-msgid "Invalid 'from' clause"
+#: src/backend_iptables.py:1102
+msgid "Rules updated (v6)"
 msgstr ""
 
-#: src/parser.py:342
-msgid "Invalid 'to' clause"
+#: src/backend_iptables.py:1110
+msgid "Rule inserted"
 msgstr ""
 
-#: src/parser.py:347
-#, python-format
-msgid "Need 'from' or 'to' with '%s'"
+#: src/backend_iptables.py:1112
+msgid "Rule updated"
 msgstr ""
 
-#: src/parser.py:374
-msgid "Invalid 'port' clause"
+#: src/backend_iptables.py:1122 src/backend_iptables.py:1139
+msgid " (skipped reloading firewall)"
 msgstr ""
 
-#: src/parser.py:383
-msgid "Mixed IP versions for 'from' and 'to'"
+#: src/backend_iptables.py:1125
+msgid "Rule deleted"
 msgstr ""
 
-#: src/parser.py:400 src/parser.py:410 src/parser.py:419
-msgid "Could not find protocol"
+#: src/backend_iptables.py:1142
+msgid "Rule added"
 msgstr ""
 
-#: src/parser.py:426
-msgid "Protocol mismatch (from/to)"
+#: src/backend_iptables.py:1159 src/backend_iptables.py:1250
+msgid "Could not update running firewall"
 msgstr ""
 
-#: src/parser.py:433
+#: src/backend_iptables.py:1214
 #, python-format
-msgid "Protocol mismatch with specified protocol %s"
-msgstr ""
-
-#: src/parser.py:552
-msgid "'route delete NUM' unsupported. Use 'delete NUM' instead."
+msgid "Could not perform '%s'"
 msgstr ""
 
-#: src/parser.py:585
-msgid "Invalid interface clause for route rule"
+#: src/backend_iptables.py:1241
+msgid "Couldn't update rules file for logging"
 msgstr ""
 
-#: src/parser.py:884
+#: src/backend_iptables.py:1299 src/backend.py:610
 #, python-format
-msgid "Command '%s' already exists"
-msgstr ""
-
-#: src/util.py:446
-msgid "Couldn't find pid (is /proc mounted?)"
+msgid "Invalid log level '%s'"
 msgstr ""
 
-#: src/util.py:450
+#: src/backend_iptables.py:1397
 #, python-format
-msgid "Couldn't find parent pid for '%s'"
+msgid "Could not find '%s'. Aborting"
 msgstr ""
 
-#: src/util.py:460
+#: src/backend_iptables.py:1409
 #, python-format
-msgid "Couldn't find '%s'"
+msgid "'%s' already exists. Aborting"
 msgstr ""
 
-#: src/util.py:466
+#: src/backend_iptables.py:1415
 #, python-format
-msgid "Could not find executable for '%s'"
+msgid "Backing up '%(old)s' to '%(new)s'\n"
 msgstr ""
 
-#: src/util.py:1026
+#: src/backend_iptables.py:1431 src/backend.py:235
 #, python-format
-msgid "Could not get statistics for '%s'"
-msgstr ""
-
-#: src/backend_iptables.py:78
-msgid "New profiles:"
+msgid "Couldn't stat '%s'"
 msgstr ""
 
-#: src/backend_iptables.py:99
+#: src/backend_iptables.py:1436
 #, python-format
-msgid "Unsupported policy for direction '%s'"
+msgid "WARN: '%s' is world writable"
 msgstr ""
 
-#: src/backend_iptables.py:159
+#: src/backend_iptables.py:1438
 #, python-format
-msgid "Default %(direction)s policy changed to '%(policy)s'\n"
-msgstr ""
-
-#: src/backend_iptables.py:161
-msgid "(be sure to update your rules accordingly)"
+msgid "WARN: '%s' is world readable"
 msgstr ""
 
-#: src/backend_iptables.py:168
-msgid "Checking raw iptables\n"
+#: src/backend.py:70
+msgid "Couldn't determine iptables version"
 msgstr ""
 
-#: src/backend_iptables.py:169
-msgid "Checking raw ip6tables\n"
+#: src/backend.py:149
+msgid "problem running sysctl"
 msgstr ""
 
-#: src/backend_iptables.py:262
-msgid "Checking iptables\n"
+#: src/backend.py:188
+msgid "Checks disabled"
 msgstr ""
 
-#: src/backend_iptables.py:264
-msgid "Checking ip6tables\n"
+#: src/backend.py:194
+msgid "ERROR: this script should not be SUID"
 msgstr ""
 
-#: src/backend_iptables.py:267 src/backend_iptables.py:568
-msgid "problem running"
+#: src/backend.py:197
+msgid "ERROR: this script should not be SGID"
 msgstr ""
 
-#: src/backend_iptables.py:273
-msgid "Status: inactive"
+#: src/backend.py:202
+msgid "You need to be root to run this script"
 msgstr ""
 
-#: src/backend_iptables.py:443
-msgid "To"
+#: src/backend.py:212
+#, python-format
+msgid "'%s' does not exist"
 msgstr ""
 
-#: src/backend_iptables.py:444
-msgid "From"
+#: src/backend.py:253
+#, python-format
+msgid "uid is %(uid)s but '%(path)s' is owned by %(st_uid)s"
 msgstr ""
 
-#: src/backend_iptables.py:445
-msgid "Action"
+#: src/backend.py:260
+#, python-format
+msgid "%s is world writable!"
 msgstr ""
 
-#: src/backend_iptables.py:461 src/backend_iptables.py:465
-msgid "\n"
+#: src/backend.py:265
+#, python-format
+msgid "%s is group writable!"
 msgstr ""
 
-#: src/backend_iptables.py:473
+#: src/backend.py:281
 #, python-format
-msgid "Default: %(in)s (incoming), %(out)s (outgoing), %(routed)s (routed)"
+msgid "'%(f)s' file '%(name)s' does not exist"
 msgstr ""
 
-#: src/backend_iptables.py:481
+#: src/backend.py:306
 #, python-format
-msgid ""
-"Status: active\n"
-"%(log)s\n"
-"%(pol)s\n"
-"%(app)s%(status)s"
+msgid "Missing policy for '%s'"
 msgstr ""
 
-#: src/backend_iptables.py:485
+#: src/backend.py:310
 #, python-format
-msgid "Status: active%s"
+msgid "Invalid policy '%(policy)s' for '%(chain)s'"
 msgstr ""
 
-#: src/backend_iptables.py:490 src/backend_iptables.py:508
-msgid "running ufw-init"
+#: src/backend.py:317
+msgid "Invalid option"
 msgstr ""
 
-#: src/backend_iptables.py:502 src/backend_iptables.py:520
+#: src/backend.py:373
 #, python-format
-msgid ""
-"problem running ufw-init\n"
-"%s"
-msgstr ""
-
-#: src/backend_iptables.py:529
-msgid "Could not set LOGLEVEL"
+msgid "Default application policy changed to '%s'"
 msgstr ""
 
-#: src/backend_iptables.py:535
-msgid "Could not load logging rules"
+#: src/backend.py:440
+msgid "No rules found for application profile"
 msgstr ""
 
-#: src/backend_iptables.py:709
+#: src/backend.py:496
 #, python-format
-msgid "Skipping malformed tuple (bad length): %s"
+msgid "Rules updated for profile '%s'"
 msgstr ""
 
-#: src/backend_iptables.py:720
-#, python-format
-msgid "Skipping malformed tuple (iface): %s"
+#: src/backend.py:502
+msgid "Couldn't update application rules"
 msgstr ""
 
-#: src/backend_iptables.py:768
+#: src/backend.py:524
 #, python-format
-msgid "Skipping malformed tuple: %s"
+msgid "Found multiple matches for '%s'. Please use exact profile name"
 msgstr ""
 
-#: src/backend_iptables.py:966
-msgid "Adding IPv6 rule failed: IPv6 not enabled"
+#: src/backend.py:527
+#, python-format
+msgid "Could not find a profile matching '%s'"
 msgstr ""
 
-#: src/backend_iptables.py:970
-#, python-format
-msgid "Skipping unsupported IPv6 '%s' rule"
+#: src/backend.py:594
+msgid "Logging: "
 msgstr ""
 
-#: src/backend_iptables.py:974
-#, python-format
-msgid "Skipping unsupported IPv4 '%s' rule"
+#: src/backend.py:598
+msgid "unknown"
 msgstr ""
 
-#: src/backend_iptables.py:977
-msgid "Must specify 'tcp' or 'udp' with multiple ports"
+#: src/backend.py:625
+msgid "Logging disabled"
 msgstr ""
 
-#: src/backend_iptables.py:989
-msgid "Skipping IPv6 application rule. Need at least iptables 1.4"
+#: src/backend.py:627
+msgid "Logging enabled"
 msgstr ""
 
-#: src/backend_iptables.py:994
+#: src/common.py:196
 #, python-format
-msgid "Invalid position '%d'"
+msgid "Bad port '%s'"
 msgstr ""
 
-#: src/backend_iptables.py:998
-msgid "Cannot specify insert and delete"
+#: src/common.py:252
+#, python-format
+msgid "Unsupported protocol '%s'"
 msgstr ""
 
-#: src/backend_iptables.py:1001
-#, python-format
-msgid "Cannot insert rule at position '%d'"
+#: src/common.py:280
+msgid "Bad source address"
 msgstr ""
 
-#: src/backend_iptables.py:1062
-msgid "Skipping inserting existing rule"
+#: src/common.py:290
+msgid "Bad destination address"
 msgstr ""
 
-#: src/backend_iptables.py:1073 src/frontend.py:415
-msgid "Could not delete non-existent rule"
+#: src/common.py:309
+msgid "Bad interface type"
 msgstr ""
 
-#: src/backend_iptables.py:1078
-msgid "Skipping adding existing rule"
+#: src/common.py:314
+msgid "Bad interface name: reserved character: '!'"
 msgstr ""
 
-#: src/backend_iptables.py:1094
-msgid "Couldn't update rules file"
+#: src/common.py:318
+msgid "Bad interface name: can't use interface aliases"
 msgstr ""
 
-#: src/backend_iptables.py:1099
-msgid "Rules updated"
+#: src/common.py:322
+msgid "Bad interface name: can't use '.' or '..'"
 msgstr ""
 
-#: src/backend_iptables.py:1101
-msgid "Rules updated (v6)"
+#: src/common.py:326
+msgid "Bad interface name: interface name is empty"
 msgstr ""
 
-#: src/backend_iptables.py:1109
-msgid "Rule inserted"
+#: src/common.py:330
+msgid "Bad interface name: interface name too long"
 msgstr ""
 
-#: src/backend_iptables.py:1111
-msgid "Rule updated"
+#: src/common.py:335
+msgid "Bad interface name"
 msgstr ""
 
-#: src/backend_iptables.py:1121
-msgid " (skipped reloading firewall)"
+#: src/common.py:349
+#, python-format
+msgid "Insert position '%s' is not a valid position"
 msgstr ""
 
-#: src/backend_iptables.py:1124
-msgid "Rule deleted"
+#: src/common.py:359
+#, python-format
+msgid "Invalid log type '%s'"
 msgstr ""
 
-#: src/backend_iptables.py:1127
-msgid "Rule added"
+#: src/common.py:367
+#, python-format
+msgid "Unsupported direction '%s'"
 msgstr ""
 
-#: src/backend_iptables.py:1144 src/backend_iptables.py:1235
-msgid "Could not update running firewall"
+#: src/common.py:386
+msgid "Could not normalize source address"
 msgstr ""
 
-#: src/backend_iptables.py:1199
-#, python-format
-msgid "Could not perform '%s'"
+#: src/common.py:397
+msgid "Could not normalize destination address"
 msgstr ""
 
-#: src/backend_iptables.py:1226
-msgid "Couldn't update rules file for logging"
+#: src/common.py:463
+msgid "Found exact match"
 msgstr ""
 
-#: src/backend_iptables.py:1382
-#, python-format
-msgid "Could not find '%s'. Aborting"
+#: src/common.py:468
+msgid "Found exact match, excepting comment"
 msgstr ""
 
-#: src/backend_iptables.py:1394
+#: src/common.py:472
 #, python-format
-msgid "'%s' already exists. Aborting"
+msgid ""
+"Found non-action/non-logtype/comment match (%(xa)s/%(ya)s/'%(xc)s' %(xl)s/"
+"%(yl)s/'%(yc)s')"
 msgstr ""
 
-#: src/backend_iptables.py:1400
+#: src/common.py:635
 #, python-format
-msgid "Backing up '%(old)s' to '%(new)s'\n"
+msgid "Improper rule syntax ('%s' specified with app rule)"
 msgstr ""
 
-#: src/backend_iptables.py:1421
+#: src/common.py:642
 #, python-format
-msgid "WARN: '%s' is world writable"
+msgid "Invalid IPv6 address with protocol '%s'"
 msgstr ""
 
-#: src/backend_iptables.py:1423
+#: src/common.py:648 src/util.py:84
 #, python-format
-msgid "WARN: '%s' is world readable"
+msgid "Invalid port with protocol '%s'"
 msgstr ""
 
-#: src/frontend.py:93
+#: src/frontend.py:103
 #, python-format
 msgid ""
 "\n"
@@ -632,6 +566,7 @@
 " %(limit)-31s add limit %(rule)s\n"
 " %(delete)-31s delete %(urule)s\n"
 " %(insert)-31s insert %(urule)s at %(number)s\n"
+" %(prepend)-31s prepend %(urule)s\n"
 " %(route)-31s add route %(urule)s\n"
 " %(route-delete)-31s delete route %(urule)s\n"
 " %(route-insert)-31s insert route %(urule)s at %(number)s\n"
@@ -650,87 +585,87 @@
 " %(appdefault)-31s set default application policy\n"
 msgstr ""
 
-#: src/frontend.py:176
+#: src/frontend.py:187
 msgid "n"
 msgstr ""
 
-#: src/frontend.py:177
+#: src/frontend.py:188
 msgid "y"
 msgstr ""
 
-#: src/frontend.py:178
+#: src/frontend.py:189
 msgid "yes"
 msgstr ""
 
-#: src/frontend.py:223
+#: src/frontend.py:234
 msgid "Firewall is active and enabled on system startup"
 msgstr ""
 
-#: src/frontend.py:230
+#: src/frontend.py:241
 msgid "Firewall stopped and disabled on system startup"
 msgstr ""
 
-#: src/frontend.py:282
+#: src/frontend.py:293
 msgid "Could not get listening status"
 msgstr ""
 
-#: src/frontend.py:351
+#: src/frontend.py:362
 msgid "Added user rules (see 'ufw status' for running firewall):"
 msgstr ""
 
-#: src/frontend.py:354
+#: src/frontend.py:365
 msgid ""
 "\n"
 "(None)"
 msgstr ""
 
-#: src/frontend.py:410 src/frontend.py:521 src/frontend.py:534
+#: src/frontend.py:421 src/frontend.py:532 src/frontend.py:545
 #, python-format
 msgid "Invalid IP version '%s'"
 msgstr ""
 
-#: src/frontend.py:441
+#: src/frontend.py:452
 msgid "Invalid position '"
 msgstr ""
 
-#: src/frontend.py:531
+#: src/frontend.py:542
 msgid "IPv6 support not enabled"
 msgstr ""
 
-#: src/frontend.py:542
+#: src/frontend.py:553
 msgid "Rule changed after normalization"
 msgstr ""
 
-#: src/frontend.py:566
+#: src/frontend.py:577
 #, python-format
 msgid "Could not back out rule '%s'"
 msgstr ""
 
-#: src/frontend.py:570
+#: src/frontend.py:581
 msgid ""
 "\n"
 "Error applying application rules."
 msgstr ""
 
-#: src/frontend.py:572
+#: src/frontend.py:583
 msgid " Some rules could not be unapplied."
 msgstr ""
 
-#: src/frontend.py:574
+#: src/frontend.py:585
 msgid " Attempted rules successfully unapplied."
 msgstr ""
 
-#: src/frontend.py:585
+#: src/frontend.py:596
 #, python-format
 msgid "Could not find rule '%s'"
 msgstr ""
 
-#: src/frontend.py:590 src/frontend.py:595
+#: src/frontend.py:601 src/frontend.py:606
 #, python-format
 msgid "Could not find rule '%d'"
 msgstr ""
 
-#: src/frontend.py:611
+#: src/frontend.py:622
 #, python-format
 msgid ""
 "Deleting:\n"
@@ -738,164 +673,225 @@
 "Proceed with operation (%(yes)s|%(no)s)? "
 msgstr ""
 
-#: src/frontend.py:643
+#: src/frontend.py:654
 msgid "Unsupported default policy"
 msgstr ""
 
-#: src/frontend.py:672 src/frontend.py:817
+#: src/frontend.py:683 src/frontend.py:828
 msgid "Firewall reloaded"
 msgstr ""
 
-#: src/frontend.py:674
+#: src/frontend.py:685
 msgid "Firewall not enabled (skipping reload)"
 msgstr ""
 
-#: src/frontend.py:691 src/frontend.py:705 src/frontend.py:742
+#: src/frontend.py:702 src/frontend.py:716 src/frontend.py:753
 msgid "Invalid profile name"
 msgstr ""
 
-#: src/frontend.py:710 src/frontend.py:892
+#: src/frontend.py:721 src/frontend.py:903
 #, python-format
 msgid "Unsupported action '%s'"
 msgstr ""
 
-#: src/frontend.py:729
+#: src/frontend.py:740
 msgid "Available applications:"
 msgstr ""
 
-#: src/frontend.py:750
+#: src/frontend.py:761
 #, python-format
 msgid "Could not find profile '%s'"
 msgstr ""
 
-#: src/frontend.py:755
+#: src/frontend.py:766
 msgid "Invalid profile"
 msgstr ""
 
-#: src/frontend.py:758
+#: src/frontend.py:769
 #, python-format
 msgid "Profile: %s\n"
 msgstr ""
 
-#: src/frontend.py:759
+#: src/frontend.py:770
 #, python-format
 msgid "Title: %s\n"
 msgstr ""
 
-#: src/frontend.py:762
+#: src/frontend.py:773
 #, python-format
 msgid ""
 "Description: %s\n"
 "\n"
 msgstr ""
 
-#: src/frontend.py:768
+#: src/frontend.py:779
 msgid "Ports:"
 msgstr ""
 
-#: src/frontend.py:770
+#: src/frontend.py:781
 msgid "Port:"
 msgstr ""
 
-#: src/frontend.py:819
+#: src/frontend.py:830
 msgid "Skipped reloading firewall"
 msgstr ""
 
-#: src/frontend.py:829
+#: src/frontend.py:840
 msgid "Cannot specify 'all' with '--add-new'"
 msgstr ""
 
-#: src/frontend.py:844
+#: src/frontend.py:855
 #, python-format
 msgid "Unknown policy '%s'"
 msgstr ""
 
-#: src/frontend.py:901
+#: src/frontend.py:912
 #, python-format
 msgid ""
 "Command may disrupt existing ssh connections. Proceed with operation "
 "(%(yes)s|%(no)s)? "
 msgstr ""
 
-#: src/frontend.py:914
+#: src/frontend.py:925
 #, python-format
 msgid ""
 "Resetting all rules to installed defaults. Proceed with operation (%(yes)s|"
 "%(no)s)? "
 msgstr ""
 
-#: src/frontend.py:918
+#: src/frontend.py:929
 #, python-format
 msgid ""
 "Resetting all rules to installed defaults. This may disrupt existing ssh "
 "connections. Proceed with operation (%(yes)s|%(no)s)? "
 msgstr ""
 
-#: src/applications.py:37
-msgid "Profiles directory does not exist"
+#: src/parser.py:110
+#, python-format
+msgid "Cannot insert rule at position '%s'"
 msgstr ""
 
-#: src/applications.py:69
-#, python-format
-msgid "Skipping '%s': couldn't stat"
+#: src/parser.py:148
+msgid "Invalid interface clause"
 msgstr ""
 
-#: src/applications.py:74
-#, python-format
-msgid "Skipping '%s': too big"
+#: src/parser.py:174
+msgid "Option 'log' not allowed here"
 msgstr ""
 
-#: src/applications.py:79
-#, python-format
-msgid "Skipping '%s': too many files read already"
+#: src/parser.py:178
+msgid "Option 'log-all' not allowed here"
 msgstr ""
 
-#: src/applications.py:93
-#, python-format
-msgid "Skipping '%s': couldn't process"
+#: src/parser.py:185
+msgid "Option 'comment' missing required argument"
 msgstr ""
 
-#: src/applications.py:100
+#: src/parser.py:191
+msgid "Comment may not contain \"'\""
+msgstr ""
+
+#: src/parser.py:233 src/parser.py:359
+msgid "Port ranges must be numeric"
+msgstr ""
+
+#: src/parser.py:242 src/util.py:87
+msgid "Bad port"
+msgstr ""
+
+#: src/parser.py:245
+msgid "Wrong number of arguments"
+msgstr ""
+
+#: src/parser.py:249
+msgid "Need 'to' or 'from' clause"
+msgstr ""
+
+#: src/parser.py:264
+msgid "Improper rule syntax"
+msgstr ""
+
+#: src/parser.py:271
 #, python-format
-msgid "Skipping '%s': name too long"
+msgid "Invalid token '%s'"
 msgstr ""
 
-#: src/applications.py:105
+#: src/parser.py:283
+msgid "Invalid 'proto' clause"
+msgstr ""
+
+#: src/parser.py:298
 #, python-format
-msgid "Skipping '%s': invalid name"
+msgid "Invalid '%s' clause"
 msgstr ""
 
-#: src/applications.py:111
+#: src/parser.py:320
+msgid "Invalid 'from' clause"
+msgstr ""
+
+#: src/parser.py:342
+msgid "Invalid 'to' clause"
+msgstr ""
+
+#: src/parser.py:347
 #, python-format
-msgid "Skipping '%s': also in /etc/services"
+msgid "Need 'from' or 'to' with '%s'"
 msgstr ""
 
-#: src/applications.py:120
+#: src/parser.py:374
+msgid "Invalid 'port' clause"
+msgstr ""
+
+#: src/parser.py:383
+msgid "Mixed IP versions for 'from' and 'to'"
+msgstr ""
+
+#: src/parser.py:400 src/parser.py:410 src/parser.py:419
+msgid "Could not find protocol"
+msgstr ""
+
+#: src/parser.py:426
+msgid "Protocol mismatch (from/to)"
+msgstr ""
+
+#: src/parser.py:433
 #, python-format
-msgid "Skipping '%s': field too long"
+msgid "Protocol mismatch with specified protocol %s"
 msgstr ""
 
-#: src/applications.py:125
+#: src/parser.py:552
+msgid "'route delete NUM' unsupported. Use 'delete NUM' instead."
+msgstr ""
+
+#: src/parser.py:585
+msgid "Invalid interface clause for route rule"
+msgstr ""
+
+#: src/parser.py:884
 #, python-format
-msgid "Skipping '%(value)s': value too long for '%(field)s'"
+msgid "Command '%s' already exists"
 msgstr ""
 
-#: src/applications.py:135
+#: src/util.py:431
+msgid "Couldn't find pid (is /proc mounted?)"
+msgstr ""
+
+#: src/util.py:435
 #, python-format
-msgid "Duplicate profile '%s', using last found"
+msgid "Couldn't find parent pid for '%s'"
 msgstr ""
 
-#: src/applications.py:178
+#: src/util.py:445
 #, python-format
-msgid "Profile '%(fn)s' missing required field '%(f)s'"
+msgid "Couldn't find '%s'"
 msgstr ""
 
-#: src/applications.py:183
+#: src/util.py:451
 #, python-format
-msgid "Profile '%(fn)s' has empty required field '%(f)s'"
+msgid "Could not find executable for '%s'"
 msgstr ""
 
-#: src/applications.py:198
+#: src/util.py:1037
 #, python-format
-msgid "Invalid ports in profile '%s'"
+msgid "Could not get statistics for '%s'"
 msgstr ""
diff -Nru ufw-0.36.1/setup.py ufw-0.36.2/setup.py
--- ufw-0.36.1/setup.py 2021-09-18 20:19:01.000000000 -0500
+++ ufw-0.36.2/setup.py 2023-05-18 08:07:39.000000000 -0500
@@ -34,7 +34,7 @@
 import shutil
 import subprocess
 
-ufw_version = '0.36.1'
+ufw_version = '0.36.2'
 
 def cmd(command):
     '''Try to execute the given command.'''
diff -Nru ufw-0.36.1/snapcraft.yaml ufw-0.36.2/snapcraft.yaml
--- ufw-0.36.1/snapcraft.yaml   2021-09-18 20:19:01.000000000 -0500
+++ ufw-0.36.2/snapcraft.yaml   2023-05-18 08:07:39.000000000 -0500
@@ -1,5 +1,5 @@
 name: ufw
-version: 0.36.1
+version: 0.36.2
 summary: ufw (Uncomplicated Firewall)
 description: ufw as a snap
 confinement: strict
diff -Nru ufw-0.36.1/src/backend_iptables.py ufw-0.36.2/src/backend_iptables.py
--- ufw-0.36.1/src/backend_iptables.py  2021-09-18 20:19:01.000000000 -0500
+++ ufw-0.36.2/src/backend_iptables.py  2023-05-18 08:07:39.000000000 -0500
@@ -1001,9 +1001,6 @@
         if position > 0 and rule.remove:
             err_msg = _("Cannot specify insert and delete")
             raise UFWError(err_msg)
-        if position > len(rules):
-            err_msg = _("Cannot insert rule at position '%d'") % position
-            raise UFWError(err_msg)
 
         # First construct the new rules list
         try:
diff -Nru ufw-0.36.1/src/backend.py ufw-0.36.2/src/backend.py
--- ufw-0.36.1/src/backend.py   2021-09-18 20:19:01.000000000 -0500
+++ ufw-0.36.2/src/backend.py   2023-05-18 08:07:39.000000000 -0500
@@ -1,6 +1,6 @@
 '''backend.py: interface for ufw backends'''
 #
-# Copyright 2008-2018 Canonical Ltd.
+# Copyright 2008-2023 Canonical Ltd.
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU General Public License version 3,
@@ -628,7 +628,15 @@
 
     def get_rules(self):
         '''Return list of all rules'''
-        return self.rules + self.rules6
+        return self.get_rules_ipv4() + self.get_rules_ipv6()
+
+    def get_rules_ipv4(self):
+        '''Return list of IPv4 rules'''
+        return self.rules
+
+    def get_rules_ipv6(self):
+        '''Return list of IPv6 rules'''
+        return self.rules6
 
     def get_rules_count(self, v6):
         '''Return number of ufw rules (not iptables rules)'''
diff -Nru ufw-0.36.1/src/frontend.py ufw-0.36.2/src/frontend.py
--- ufw-0.36.1/src/frontend.py  2021-09-18 20:19:01.000000000 -0500
+++ ufw-0.36.2/src/frontend.py  2023-05-18 08:07:39.000000000 -0500
@@ -1,6 +1,6 @@
 '''frontend.py: frontend interface for ufw'''
 #
-# Copyright 2008-2018 Canonical Ltd.
+# Copyright 2008-2023 Canonical Ltd.
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU General Public License version 3,
@@ -31,8 +31,17 @@
     p = ufw.parser.UFWParser()
 
     # Basic commands
-    for i in ['enable', 'disable', 'help', '--help', 'version', '--version', \
-              'reload', 'reset' ]:
+    for i in [
+        "enable",
+        "disable",
+        "help",
+        "--help",
+        "-h",
+        "version",
+        "--version",
+        "reload",
+        "reset",
+    ]:
         p.register_command(ufw.parser.UFWCommandBasic(i))
 
     # Application commands
@@ -74,8 +83,9 @@
            argv[idx].lower() in rule_commands:
             argv.insert(idx, 'rule')
 
-    if len(argv) < 2 or ('--dry-run' in argv and len(argv) < 3):
-        error("not enough args") # pragma: no cover
+    if len(argv) < 2 or ("--dry-run" in argv and len(argv) < 3):
+        error("not enough args", do_exit=False)  # pragma: no cover
+        raise ValueError()
 
     try:
         pr = p.parse_command(argv[1:])
diff -Nru ufw-0.36.1/src/ufw ufw-0.36.2/src/ufw
--- ufw-0.36.1/src/ufw  2021-09-18 20:19:01.000000000 -0500
+++ ufw-0.36.2/src/ufw  2023-05-18 08:07:39.000000000 -0500
@@ -2,7 +2,7 @@
 #
 # ufw: front-end for Linux firewalling (cli)
 #
-# Copyright 2008-2018 Canonical Ltd.
+# Copyright 2008-2023 Canonical Ltd.
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU General Public License version 3,
@@ -103,12 +103,12 @@
     except Exception:
         raise
 
-    if pr.action == "help" or pr.action == "--help":
+    if pr.action == "help" or pr.action == "--help" or pr.action == "-h":
         msg(ufw.frontend.get_command_help())
         sys.exit(0)
     elif pr.action == "version" or pr.action == "--version":
         msg(ufw.common.programName + " " + version)
-        msg("Copyright 2008-2018 Canonical Ltd.")
+        msg("Copyright 2008-2023 Canonical Ltd.")
         sys.exit(0)
 
     try:
diff -Nru ufw-0.36.1/src/ufw-init-functions ufw-0.36.2/src/ufw-init-functions
--- ufw-0.36.1/src/ufw-init-functions   2021-09-18 17:00:21.000000000 -0500
+++ ufw-0.36.2/src/ufw-init-functions   2023-05-16 09:51:25.000000000 -0500
@@ -168,29 +168,6 @@
             AFTER_RULES="$RULES_PATH/after${type}.rules"
             USER_RULES="$USER_PATH/user${type}.rules"
 
-            # set the default policy
-            input_pol="$DEFAULT_INPUT_POLICY"
-            if [ "$DEFAULT_INPUT_POLICY" = "REJECT" ]; then
-                input_pol="DROP"
-            fi
-
-            output_pol="$DEFAULT_OUTPUT_POLICY"
-            if [ "$DEFAULT_OUTPUT_POLICY" = "REJECT" ]; then
-                output_pol="DROP"
-            fi
-
-            forward_pol="$DEFAULT_FORWARD_POLICY"
-            if [ "$DEFAULT_FORWARD_POLICY" = "REJECT" ]; then
-                forward_pol="DROP"
-            fi
-
-            printf "*filter\n"\
-"# builtin chains\n"\
-":INPUT %s [0:0]\n"\
-":FORWARD %s [0:0]\n"\
-":OUTPUT %s [0:0]\n"\
-"COMMIT\n" $input_pol $forward_pol $output_pol | $exe-restore -n || error="yes"
-
             # flush the chains (if they exist)
             if $exe -L ufw${type}-before-logging-input -n >/dev/null 2>&1 ; 
then
                 delete_chains $type || error="yes"
@@ -378,6 +355,32 @@
                 out="${out}\nCouldn't find '$USER_RULES'"
                 error="yes"
             fi
+
+            # set the default policy (do this after loading rules so not to
+            # break network rootfs w/ INPUT DROP during ufw init. LP: 1946804)
+            input_pol="$DEFAULT_INPUT_POLICY"
+            if [ "$DEFAULT_INPUT_POLICY" = "REJECT" ]; then
+                input_pol="DROP"
+            fi
+
+            output_pol="$DEFAULT_OUTPUT_POLICY"
+            if [ "$DEFAULT_OUTPUT_POLICY" = "REJECT" ]; then
+                output_pol="DROP"
+            fi
+
+            forward_pol="$DEFAULT_FORWARD_POLICY"
+            if [ "$DEFAULT_FORWARD_POLICY" = "REJECT" ]; then
+                forward_pol="DROP"
+            fi
+
+            # Since we're setting the default policy last, '-n/--noflush' is
+            # important here so we don't undo what we've loaded so far.
+            printf "*filter\n"\
+"# builtin chains\n"\
+":INPUT %s [0:0]\n"\
+":FORWARD %s [0:0]\n"\
+":OUTPUT %s [0:0]\n"\
+"COMMIT\n" $input_pol $forward_pol $output_pol | $exe-restore -n || error="yes"
         done
 
         if [ ! -z "$IPT_SYSCTL" ] && [ -s "$IPT_SYSCTL" ]; then
diff -Nru ufw-0.36.1/src/util.py ufw-0.36.2/src/util.py
--- ufw-0.36.1/src/util.py      2021-09-18 20:19:01.000000000 -0500
+++ ufw-0.36.2/src/util.py      2023-05-18 08:07:39.000000000 -0500
@@ -1,6 +1,6 @@
 '''util.py: utility functions for ufw'''
 #
-# Copyright 2008-2018 Canonical Ltd.
+# Copyright 2008-2023 Canonical Ltd.
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU General Public License version 3,
@@ -38,9 +38,9 @@
 
 # We support different protocols these days and only come combinations are
 # valid
-supported_protocols = [ 'tcp', 'udp', 'ipv6', 'esp', 'ah', 'igmp', 'gre' ]
-portless_protocols = [ 'ipv6', 'esp', 'ah', 'igmp', 'gre' ]
-ipv4_only_protocols = [ 'ipv6', 'igmp' ]
+supported_protocols = ["tcp", "udp", "ipv6", "esp", "ah", "igmp", "gre", 
"vrrp"]
+portless_protocols = ["ipv6", "esp", "ah", "igmp", "gre", "vrrp"]
+ipv4_only_protocols = ["ipv6", "igmp"]
 
 
 def get_services_proto(port):
@@ -416,7 +416,9 @@
     # LP: #1101304
     # 9983 (cmd) S 923 ...
     # 9983 (cmd with spaces) S 923 ...
-    ppid = open(name).readlines()[0].split(')')[1].split()[1]
+    # LP: #2015645
+    # 229 (cmd(withparen)) S 228 ...
+    ppid = open(name).readlines()[0].rsplit(")", 1)[1].split()[1]
 
     return int(ppid)
 
@@ -1083,8 +1085,16 @@
 def hex_decode(h):
     '''Take a hex string and convert it to a string'''
     if sys.version_info[0] < 3:
-        return h.decode(encoding='hex').decode('utf-8')
-    return binascii.unhexlify(h).decode('utf-8')
+        return h.decode(encoding="hex").decode("utf-8")
+    # unhexlify requires an even length string, which should normally happen
+    # since hex_encode() will create a string and decode to ascii, which has 2
+    # bytes per character. If we happen to get an odd length string, instead of
+    # tracing back, truncate it by one character and move on. This works
+    # reasonably well in some cases, but might result in a UnicodeDecodeError,
+    # so use backslashreplace in that case.
+    return binascii.unhexlify("%s" % (h[:-1] if len(h) % 2 else h)).decode(
+        "utf-8", "backslashreplace"
+    )
 
 
 def create_lock(lockfile='/run/ufw.lock', dryrun=False):
diff -Nru ufw-0.36.1/tests/bugs/misc/result ufw-0.36.2/tests/bugs/misc/result
--- ufw-0.36.1/tests/bugs/misc/result   2018-12-14 12:25:55.000000000 -0600
+++ ufw-0.36.2/tests/bugs/misc/result   2023-05-16 09:51:25.000000000 -0500
@@ -163,6 +163,38 @@
 29: --dry-run
 ERROR: not enough args
 
+Usage: ufw COMMAND
+
+Commands:
+ enable                          enables the firewall
+ disable                         disables the firewall
+ default ARG                     set default policy
+ logging LEVEL                   set logging to LEVEL
+ allow ARGS                      add allow rule
+ deny ARGS                       add deny rule
+ reject ARGS                     add reject rule
+ limit ARGS                      add limit rule
+ delete RULE|NUM                 delete RULE
+ insert NUM RULE                 insert RULE at NUM
+ prepend RULE                    prepend RULE
+ route RULE                      add route RULE
+ route delete RULE|NUM           delete route RULE
+ route insert NUM RULE           insert route RULE at NUM
+ reload                          reload firewall
+ reset                           reset firewall
+ status                          show firewall status
+ status numbered                 show firewall status as numbered list of RULES
+ status verbose                  show verbose firewall status
+ show ARG                        show firewall report
+ version                         display version information
+
+Application profile commands:
+ app list                        list application profiles
+ app info PROFILE                show information on PROFILE
+ app update PROFILE              update PROFILE
+ app default ARG                 set default application policy
+
+
 
 Bug #787955
 30: --dry-run status
diff -Nru ufw-0.36.1/tests/check-requirements 
ufw-0.36.2/tests/check-requirements
--- ufw-0.36.1/tests/check-requirements 2021-09-18 19:50:19.000000000 -0500
+++ ufw-0.36.2/tests/check-requirements 2023-05-16 09:51:25.000000000 -0500
@@ -59,7 +59,7 @@
         echo "pass (binary: $exe, version: $v, py2)"
         found_python="yes"
         break
-    elif echo "$v" | grep -q "^3.[2-8]"; then
+    elif echo "$v" | grep -q "^3.[1-9][0-9]*"; then
         echo "pass (binary: $exe, version: $v, py3)"
         found_python="yes"
         break
@@ -254,18 +254,21 @@
 done
 
 # check and warn if various firewall applications are installed
+echo "== System =="
+echo -n "Other firewall applications:"
 found=
 for exe in apf arno-iptables-firewall ferm firehol firewalld ipkungfu 
iptables-persistent netfilter-persistent pyroman uruk ; do
     if PATH=/sbin:/usr/sbin:/bin:/usr/bin which "$exe" >/dev/null 2>&1; then
         found="$found $exe"
     fi
 done
-if [ ! -z "$found" ]; then
-    echo "WARN: detected other firewall applications:"
-    echo "$found"
-    echo "(if enabled, these applications may interfere with ufw)"
-    echo ""
+if [ -z "$found" ]; then
+    echo " pass"
+else
+    echo -n "$found"
+    echo -n " (if enabled, may interfere with ufw)"
 fi
+echo ""
 
 if [ -n "$error" ] || [ -n "$error_runtime" ]; then
     if [ -n "$error" ]; then
diff -Nru ufw-0.36.1/tests/root/bugs/result ufw-0.36.2/tests/root/bugs/result
--- ufw-0.36.1/tests/root/bugs/result   2021-09-18 19:50:19.000000000 -0500
+++ ufw-0.36.2/tests/root/bugs/result   2023-05-18 08:06:28.000000000 -0500
@@ -67,14 +67,14 @@
 ip6tables -L -n:
 Chain INPUT (policy DROP)
 target     prot opt source               destination         
-ACCEPT     all      ::/0                 ::/0                
+ACCEPT     TST  --  ::/0                 ::/0                
 
 Chain FORWARD (policy DROP)
 target     prot opt source               destination         
 
 Chain OUTPUT (policy DROP)
 target     prot opt source               destination         
-ACCEPT     all      ::/0                 ::/0                
+ACCEPT     TST  --  ::/0                 ::/0                
 Bug #260881
 Setting IPV6 to no
 6: disable
@@ -94,7 +94,7 @@
 
 
 iptables -L -n:
-ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 /* 
'dapp_Apache' */
+ACCEPT     TST    --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 /* 
'dapp_Apache' */
 
 10: delete allow Apache
 WARN: Checks disabled
diff -Nru ufw-0.36.1/tests/root/bugs/runtest.sh 
ufw-0.36.2/tests/root/bugs/runtest.sh
--- ufw-0.36.1/tests/root/bugs/runtest.sh       2021-09-18 19:50:19.000000000 
-0500
+++ ufw-0.36.2/tests/root/bugs/runtest.sh       2023-05-18 08:06:28.000000000 
-0500
@@ -38,7 +38,8 @@
 echo "/lib/ufw/ufw-init force-reload:" >> $TESTTMP/result
 $TESTSTATE/ufw-init force-reload 2>/dev/null >> $TESTTMP/result
 echo "ip6tables -L -n:" >> $TESTTMP/result
-ip6tables -L -n 2>/dev/null >> $TESTTMP/result
+# normalize 'ACCEPT {all,tcp}' and 'ACCEPT N' for old/new kernel/iptables
+ip6tables -L -n | sed 's/^ACCEPT \+[a-z0-9]\+ [ -]\+/ACCEPT     TST  --  /' 
2>/dev/null >> $TESTTMP/result
 
 echo "Bug #260881" >> $TESTTMP/result
 echo "Setting IPV6 to no" >> $TESTTMP/result
@@ -48,7 +49,8 @@
 do_cmd "0"  allow Apache
 do_cmd "0"  delete deny Apache
 echo "iptables -L -n:" >> $TESTTMP/result
-iptables -L -n 2>/dev/null | grep -A1 "80" >> $TESTTMP/result
+# normalize 'ACCEPT {all,tcp}' and 'ACCEPT N' for old/new kernel/iptables
+iptables -L -n | sed 's/^ACCEPT \+[a-z0-9]\+ [ -]\+/ACCEPT     TST  --  /' 
2>/dev/null | grep -A1 "80" >> $TESTTMP/result
 do_cmd "0"  delete allow Apache
 echo "iptables -L -n:" >> $TESTTMP/result
 iptables -L -n 2>/dev/null | grep -A1 "80" >> $TESTTMP/result
diff -Nru ufw-0.36.1/tests/root/live/result ufw-0.36.2/tests/root/live/result
--- ufw-0.36.1/tests/root/live/result   2021-09-18 19:50:19.000000000 -0500
+++ ufw-0.36.2/tests/root/live/result   2023-05-18 08:06:28.000000000 -0500
@@ -634,7 +634,7 @@
 86: enable
 
 
-ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            /* 
ufw_test_builtins */
+ACCEPT     TST  --  0.0.0.0/0            0.0.0.0/0            /* 
ufw_test_builtins */
 Testing status numbered
 Setting IPV6 to yes
 87: disable
diff -Nru ufw-0.36.1/tests/root/live/runtest.sh 
ufw-0.36.2/tests/root/live/runtest.sh
--- ufw-0.36.1/tests/root/live/runtest.sh       2021-09-18 19:50:19.000000000 
-0500
+++ ufw-0.36.2/tests/root/live/runtest.sh       2023-05-18 08:06:28.000000000 
-0500
@@ -110,7 +110,8 @@
         echo iptables -I INPUT -j ACCEPT -m comment --comment $str >> 
$TESTTMP/result
         iptables -I INPUT -j ACCEPT -m comment --comment $str >> 
$TESTTMP/result
         do_cmd "0" nostats enable
-        iptables -n -L INPUT 2>/dev/null | grep "$str" >> $TESTTMP/result
+        # normalize 'ACCEPT {all,tcp}' and 'ACCEPT N' for old/new 
kernel/iptables
+        iptables -n -L INPUT | sed 's/^ACCEPT \+[a-z0-9]\+ [ -]\+/ACCEPT     
TST  --  /' 2>/dev/null | grep "$str" >> $TESTTMP/result
         iptables -D INPUT -j ACCEPT -m comment --comment $str 2>/dev/null
 done
 
diff -Nru ufw-0.36.1/tests/root/live_route/result 
ufw-0.36.2/tests/root/live_route/result
--- ufw-0.36.1/tests/root/live_route/result     2018-12-14 12:25:55.000000000 
-0600
+++ ufw-0.36.2/tests/root/live_route/result     2023-05-18 08:06:28.000000000 
-0500
@@ -572,7 +572,7 @@
 79: enable
 
 
-ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            /* 
ufw_test_builtins */
+ACCEPT     TST  --  0.0.0.0/0            0.0.0.0/0            /* 
ufw_test_builtins */
 Testing status numbered
 Setting IPV6 to yes
 80: disable
diff -Nru ufw-0.36.1/tests/root/live_route/runtest.sh 
ufw-0.36.2/tests/root/live_route/runtest.sh
--- ufw-0.36.1/tests/root/live_route/runtest.sh 2021-09-18 19:50:19.000000000 
-0500
+++ ufw-0.36.2/tests/root/live_route/runtest.sh 2023-05-18 08:06:28.000000000 
-0500
@@ -99,7 +99,8 @@
         echo iptables -I FORWARD -j ACCEPT -m comment --comment $str >> 
$TESTTMP/result
         iptables -I FORWARD -j ACCEPT -m comment --comment $str >> 
$TESTTMP/result
         do_cmd "0" nostats enable
-        iptables -n -L FORWARD 2>/dev/null | grep "$str" >> $TESTTMP/result
+        # normalize 'ACCEPT {all,tcp}' and 'ACCEPT N' for old/new 
kernel/iptables
+        iptables -n -L FORWARD | sed 's/^ACCEPT \+[a-z0-9]\+ [ -]\+/ACCEPT     
TST  --  /' 2>/dev/null | grep "$str" >> $TESTTMP/result
         iptables -D FORWARD -j ACCEPT -m comment --comment $str 2>/dev/null
 done
 
diff -Nru ufw-0.36.1/tests/unit/test_applications.py 
ufw-0.36.2/tests/unit/test_applications.py
--- ufw-0.36.1/tests/unit/test_applications.py  2018-12-14 12:25:55.000000000 
-0600
+++ ufw-0.36.2/tests/unit/test_applications.py  2023-05-18 08:07:39.000000000 
-0500
@@ -117,6 +117,9 @@
                     {'title': 'bad protocol - ipv6',
                      'description': 'desc',
                      'ports': '80/ipv6'},
+                    {'title': 'bad protocol - vrrp',
+                     'description': 'desc',
+                     'ports': '80/vrrp'},
                     ]
         for p in profiles:
             print(" %s" % p)
diff -Nru ufw-0.36.1/tests/unit/test_common.py 
ufw-0.36.2/tests/unit/test_common.py
--- ufw-0.36.1/tests/unit/test_common.py        2021-09-18 19:50:19.000000000 
-0500
+++ ufw-0.36.2/tests/unit/test_common.py        2023-05-18 08:07:39.000000000 
-0500
@@ -261,7 +261,7 @@
     def test_set_protocol(self):
         '''Test set_protocol()'''
         r = self.rules["any"]
-        for proto in ['any', 'tcp', 'udp', 'ipv6', 'esp', 'ah']:
+        for proto in ['any', 'tcp', 'udp', 'ipv6', 'esp', 'ah', 'vrrp']:
             r.set_protocol(proto)
             self.assertEquals(proto, r.protocol, "%s != %s" %
                               (proto, r.protocol))
diff -Nru ufw-0.36.1/tests/unit/test_parser.py 
ufw-0.36.2/tests/unit/test_parser.py
--- ufw-0.36.1/tests/unit/test_parser.py        2021-09-18 19:50:19.000000000 
-0500
+++ ufw-0.36.2/tests/unit/test_parser.py        2023-05-18 08:07:39.000000000 
-0500
@@ -428,6 +428,7 @@
                 ['deny', 'to', 'any', 'proto', 'ipv6'],
                 ['allow', 'to', 'any', 'proto', 'igmp'],
                 ['reject', 'to', 'any', 'proto', 'esp'],
+                ['allow', 'to', 'any', 'proto', 'vrrp'],
                 ['deny', 'to', '224.0.0.1', 'proto', 'igmp'],
                 ['deny', 'in', 'on', 'eth0', 'to', '224.0.0.1', 'proto', \
                  'igmp'],
@@ -435,6 +436,8 @@
                  'gre'],
                 ['deny', 'to', 'any', 'proto', 'ah'],
                 ['allow', 'out', 'on', 'br_lan'],
+                ['allow', 'in', 'on', 'eth0', 'to', '192.168.0.1', 'from', \
+                 '224.0.0.0/24', 'proto', 'vrrp'],
                ]
         count = 0
         for rtype in ['route', 'rule']:
@@ -524,6 +527,8 @@
                  ufw.common.UFWError),
                 (['rule', 'deny', 'to', 'any', 'port', '22', 'proto', 'gre'],
                  ufw.common.UFWError),
+                (['rule', 'deny', 'to', 'any', 'port', '22', 'proto', 'vrrp'],
+                 ufw.common.UFWError),
                 (['rule', 'allow', 'to', '192.168.0.0/16', 'app', 'Samba',
                   'from', '192.168.0.0/16', 'port', 'tcpmux'],
                   ufw.common.UFWError),
diff -Nru ufw-0.36.1/tests/unit/test_util.py ufw-0.36.2/tests/unit/test_util.py
--- ufw-0.36.1/tests/unit/test_util.py  2018-12-14 12:25:55.000000000 -0600
+++ ufw-0.36.2/tests/unit/test_util.py  2023-05-18 08:07:39.000000000 -0500
@@ -741,6 +741,42 @@
         tests.unit.support.check_for_exception(self, IOError, \
                                                ufw.util.get_ppid, 0)
 
+    def test_get_ppid_no_space(self):
+        """Test get_ppid() no space"""
+        if sys.version_info[0] < 3:
+            return tests.unit.support.skipped(self, "skipping with python2")
+        import unittest.mock
+
+        m = unittest.mock.mock_open(read_data="9983 (cmd) S 923 9983 ...\n")
+        with unittest.mock.patch("builtins.open", m):
+            with unittest.mock.patch("os.path.isfile", return_value=True):
+                ppid = ufw.util.get_ppid(9983)
+                self.assertEquals(ppid, 923, "%d' != '923'" % ppid)
+
+    def test_get_ppid_with_space(self):
+        """Test get_ppid() with space"""
+        if sys.version_info[0] < 3:
+            return tests.unit.support.skipped(self, "skipping with python2")
+        import unittest.mock
+
+        m = unittest.mock.mock_open(read_data="9983 (cmd with space) S 923 
9983 ...\n")
+        with unittest.mock.patch("builtins.open", m):
+            with unittest.mock.patch("os.path.isfile", return_value=True):
+                ppid = ufw.util.get_ppid(9983)
+                self.assertEquals(ppid, 923, "%d' != '923'" % ppid)
+
+    def test_get_ppid_with_parens(self):
+        """Test get_ppid() with parens"""
+        if sys.version_info[0] < 3:
+            return tests.unit.support.skipped(self, "skipping with python2")
+        import unittest.mock
+
+        m = unittest.mock.mock_open(read_data="9983 (cmd(paren)) S 923 9983 
...\n")
+        with unittest.mock.patch("builtins.open", m):
+            with unittest.mock.patch("os.path.isfile", return_value=True):
+                ppid = ufw.util.get_ppid(9983)
+                self.assertEquals(ppid, 923, "%d' != '923'" % ppid)
+
     def test_under_ssh(self):
         '''Test under_ssh()'''
         # this test could be running under ssh, so can't do anything more
@@ -1025,6 +1061,25 @@
         result = ufw.util.hex_decode(s)
         self.assertEquals(expected, result)
 
+        # test odd length string mitigation by truncating one hex-digit. This
+        # should result in the last (odd) hex digit being dropped and a decoded
+        # string of one less character
+        expected = "foo👍bar字ba"
+        if sys.version_info[0] < 3:
+            expected = u"foo👍bar字ba"
+        result = ufw.util.hex_decode(s[:-1])
+        self.assertEquals(expected, result)
+
+        # test odd length string mitigation by removing first hex-digit. This
+        # should result in the last (odd) hex digit being dropped, but since
+        # the first hex digit was removed, the byte sequence is shifted by one
+        # which causes the whole string to be 'backslashreplace'd.
+        expected = "f\\xf6\\xff\t\\xf9\x18\\xd6&\x17.Z\\xd9v&\x17"
+        if sys.version_info[0] < 3:
+            expected = u"f\\xf6\\xff\t\\xf9\x18\\xd6&\x17.Z\\xd9v&\x17"
+        result = ufw.util.hex_decode(s[1:])
+        self.assertEquals(expected, result)
+
     def test_create_lock(self):
         '''Test create_lock()'''
         lock = ufw.util.create_lock(dryrun=True)

Reply via email to