Hello community,

here is the log from the commit of package SuSEfirewall2 for openSUSE:Factory 
checked in at 2017-11-30 12:38:37
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/SuSEfirewall2 (Old)
 and      /work/SRC/openSUSE:Factory/.SuSEfirewall2.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "SuSEfirewall2"

Thu Nov 30 12:38:37 2017 rev:87 rq:546247 version:3.6.376

Changes:
--------
--- /work/SRC/openSUSE:Factory/SuSEfirewall2/SuSEfirewall2.changes      
2017-10-28 14:17:05.817616093 +0200
+++ /work/SRC/openSUSE:Factory/.SuSEfirewall2.new/SuSEfirewall2.changes 
2017-11-30 12:38:39.016624239 +0100
@@ -1,0 +2,17 @@
+Tue Nov 28 13:42:07 UTC 2017 - [email protected]
+
+- logging: correctly set the PID of the logging process
+
+-------------------------------------------------------------------
+Tue Nov 28 10:33:24 UTC 2017 - [email protected]
+
+- main script: remove duplicate rules in the rpc rules area (bnc#1069760)
+- main script: support --trace messages
+
+-------------------------------------------------------------------
+Thu Nov 23 13:37:44 UTC 2017 - [email protected]
+
+- Replace references to /var/adm/fillup-templates with new 
+  %_fillupdir macro (boo#1069468)
+
+-------------------------------------------------------------------

Old:
----
  SuSEfirewall2-3.6.369.tar.bz2

New:
----
  SuSEfirewall2-3.6.376.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ SuSEfirewall2.spec ++++++
--- /var/tmp/diff_new_pack.5oOHEB/_old  2017-11-30 12:38:39.840594277 +0100
+++ /var/tmp/diff_new_pack.5oOHEB/_new  2017-11-30 12:38:39.840594277 +0100
@@ -17,9 +17,14 @@
 # icecream 0
 
 
+#Compat macro for new _fillupdir macro introduced in Nov 2017
+%if ! %{defined _fillupdir}
+  %define _fillupdir /var/adm/fillup-templates
+%endif
+
 %define newname SUSEfirewall2
 Name:           SuSEfirewall2
-Version:        3.6.369
+Version:        3.6.376
 Release:        0
 Url:            http://en.opensuse.org/SuSEfirewall2
 PreReq:         /bin/sed textutils fileutils grep filesystem
@@ -56,8 +61,8 @@
 
 %install
 make DESTDIR="%{buildroot}" install install_doc
-install -d -m 755 %{buildroot}/var/adm/fillup-templates/
-install -m 644 SuSEfirewall2.sysconfig 
%{buildroot}/var/adm/fillup-templates/sysconfig.SuSEfirewall2
+install -d -m 755 %{buildroot}%{_fillupdir}/
+install -m 644 SuSEfirewall2.sysconfig 
%{buildroot}%{_fillupdir}/sysconfig.SuSEfirewall2
 install -D -m 644 SuSEfirewall2.sysconfig 
%{buildroot}/etc/sysconfig/SuSEfirewall2
 install -d -m 755 %{buildroot}%{_datadir}/susehelp/meta/Manuals/Productivity
 install -m 644 doc/SuSEfirewall2-doc.desktop \
@@ -99,7 +104,7 @@
 /usr/lib/systemd/system/SuSEfirewall2_init.service
 /usr/share/SuSEfirewall2/defaults/50-default.cfg
 /usr/share/SuSEfirewall2/rpcusers
-/var/adm/fillup-templates/sysconfig.SuSEfirewall2
+%{_fillupdir}/sysconfig.SuSEfirewall2
 
 %pre
 %service_add_pre SuSEfirewall2.service

++++++ SuSEfirewall2-3.6.369.tar.bz2 -> SuSEfirewall2-3.6.376.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/SuSEfirewall2-3.6.369/SuSEfirewall2 
new/SuSEfirewall2-3.6.376/SuSEfirewall2
--- old/SuSEfirewall2-3.6.369/SuSEfirewall2     2017-10-17 13:18:06.000000000 
+0200
+++ new/SuSEfirewall2-3.6.376/SuSEfirewall2     2017-11-28 14:32:03.000000000 
+0100
@@ -118,7 +118,7 @@
        pri="-p auth.warn"
     fi
     shift
-    /bin/logger $dashs $pri -t SuSEfirewall2 "$*"
+    /bin/logger $dashs $pri --id=$$ -t SuSEfirewall2 "$*"
 }
 
 message()
@@ -138,6 +138,13 @@
     message ${FUNCNAME[1]} $*
 }
 
+tracemessage()
+{
+    $TRACE || return
+
+    message ${FUNCNAME[1]} $*
+}
+
 deprecated()
 {
     warning "$@ is deprecated and will likely be removed in the future."
@@ -298,6 +305,7 @@
 
 ACTION="start"
 MODE="standard"
+TRACE=false
 INITSCRIPTS="" # on|off
 needconfig=
 needlock=1
@@ -309,7 +317,7 @@
     quiet=1
 fi
 
-getopttmp=`/usr/bin/getopt -o hqi:s: --long 
help,scriptsdir:,batch,nobatch,file:,debug,test,bootlock,bootunlock,quiet,interface:,service:
 \
+getopttmp=`/usr/bin/getopt -o hqi:s: --long 
help,scriptsdir:,batch,nobatch,file:,debug,trace,test,bootlock,bootunlock,quiet,interface:,service:
 \
      -n 'SuSEfirewall2' -- "$@"`
 
 [ $? != 0 ] && die 1 "getopt error"
@@ -324,6 +332,7 @@
                 --scriptsdir) SCRIPTSDIR="$2" ; shift 2 ;;
                 --test) MODE="test" ; shift ;;
                 --debug) MODE="debug"; needlock=0 ; shift ;;
+                --trace) TRACE=true ; shift ;;
                 --bootlock) create_bootlock=1 ; shift ;;
                 --bootunlock) remove_bootlock=1 ; shift ;;
                 -h|--help) help ; shift ;;
@@ -2452,7 +2461,7 @@
 {
        local zone chain services comment
        local selected="$1"
-       [ -z "$add_portmapper" ] && add_portmapper=true
+       [ -z "$add_portmapper" ] && local add_portmapper=true
        [ -z "$update_rpc" ] && update_rpc=false
 
        for zone in $input_zones; do
@@ -2946,9 +2955,79 @@
        done
 }
 
+# bnc#1069760
+# in some circumstances like with rpc service rules for portmapper
+# port 111 we can end up with duplicate rules in the rule set. It's
+# difficult to avoid setting them in the first place due to
+# customizations by users, different packages dropping rpc service
+# files not according to standard (specifying portmap instead of portmapper),
+# therefore we're implicitly adding portmapper for each rpc service setup ...
+#
+# so this is not elegant but involves the smallest risk of breaking
+# something: iterate over the rules we've set know and remove unneeded
+# ones
+function erase_duplicates
+{
+       for zone in $all_zones; do
+               for chain in input forward; do
+                       chain="${chain}_${zone}"
+                       # use _BIN variants here, to avoid iptables-batch
+                       # getting in our way
+                       for iptables in $IPTABLES_BIN $IP6TABLES_BIN; do
+                               erase_duplicates_in_chain "$iptables" "$chain"
+                       done
+               done
+       done
+}
+
+function erase_duplicates_in_chain
+{
+       local iptables="$1"
+       local chain="$2"
+
+       [ -z "$chain" -o -z "$iptables" ] && return 1
+
+       # keep track of duplicate rules via an associative array
+       declare -A ruleset
+       declare -A rulemap
+
+       local ORIG_IFS="$IFS"
+       local replace='s/-m comment --comment "[^"]\+" //g'
+       local rulenum=1
+       local dups=""
+       local rule
+
+       # - tail: ignore the first rule (chain creation rule, not counted)
+       # - sed: cut out the comments from the rules, because equal rules
+       #        can have different comments for the update-rpc logic
+
+       IFS=$'\n'; for rule in `$iptables -S "$chain" | /usr/bin/tail -n +2 | 
/usr/bin/sed $replace`; do
+               if [ ${ruleset[$rule]+abc} ]; then
+                       # it's important to put higher numbers first, because
+                       # otherwise we'll screw up order upon delete
+                       dups="$rulenum $dups"
+               else
+                       ruleset[$rule]=true
+               fi
+
+               rulemap[$rulenum]=$rule
+               rulenum=$(($rulenum + 1))
+       done
+
+       IFS="$ORIG_IFS"
+
+       for rulenum in $dups; do
+               rule=${rulemap[$rulenum]}
+               tracemessage "Removing duplicate rule nr. $rulenum from $chain: 
$rule"
+               $iptables -D "$chain" $rulenum
+       done
+}
+
 # perform some final actions after all rules have been setup
 function fw_after_finished
 {
+       erase_duplicates
+
        # check whether libvirtd is running and trigger it to reinstate
        # firewall rules, if necessary. See bsc#884398
        /bin/systemctl --quiet is-active libvirtd || return
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/SuSEfirewall2-3.6.369/obs/mkpackage 
new/SuSEfirewall2-3.6.376/obs/mkpackage
--- old/SuSEfirewall2-3.6.369/obs/mkpackage     2017-10-17 13:18:06.000000000 
+0200
+++ new/SuSEfirewall2-3.6.376/obs/mkpackage     2017-11-28 14:32:03.000000000 
+0100
@@ -25,7 +25,19 @@
 if [ "`git --no-pager diff --name-only|wc -l`" != '0' -o "`git --no-pager diff 
--name-only --cached|wc -l`" != 0 ]; then
        echo "*** Error: uncomitted changes"
        echo "run 'git add file' to add files, 'git commit -a' to commit 
changes"
-       exit 1
+       if [ ! -t 0 ]; then
+               exit 1
+       fi
+       echo "Do you want to continue anyway (y/n)?"
+       echo "The resulting package will not contain the uncommited changes."
+       while true; do
+               read CONT
+               if [ "$CONT" = "y" ]; then
+                       break
+               else
+                       exit 1
+               fi
+       done
 fi
 
 cd "$dstdir"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/SuSEfirewall2-3.6.369/tests/regtest.py 
new/SuSEfirewall2-3.6.376/tests/regtest.py
--- old/SuSEfirewall2-3.6.369/tests/regtest.py  1970-01-01 01:00:00.000000000 
+0100
+++ new/SuSEfirewall2-3.6.376/tests/regtest.py  2017-11-28 14:32:03.000000000 
+0100
@@ -0,0 +1,428 @@
+#!/usr/bin/python3
+
+from __future__ import print_function
+import os, sys
+import argparse
+import tempfile
+import datetime
+import shutil
+import subprocess
+
+try:
+       import paramiko
+       # there's a plethora of issues in paramiko regarding host key
+       # selection like found in this PR:
+       # https://github.com/paramiko/paramiko/issues/350
+       #
+       # it seems paramiko uses different preferences than openssh itself.
+       # openssh uses ecdsa while paramiko sticks to rsa. rsa keys are not in
+       # known hosts, leading to "not found in known_hosts" errors which are
+       # confusing.
+       #
+       # current Leap 42.3 version still doesn't fix this. this here is hacky
+       # workaround that doesn't require changing the known hosts policy to
+       # auto-add.
+       pks = paramiko.transport.Transport._preferred_keys
+       paramiko.transport.Transport._preferred_keys = ('ecdsa-sha2-nistp256',) 
+ pks
+except ImportError:
+       print("Failed to load paramiko module.\n"
+                       "Try installing python3-paramiko\n",
+                       file = sys.stderr,
+                       end = '')
+       sys.exit(1)
+
+# this script provides some minimum regression testing of sf2 changes.
+
+class SshFailed(Exception):
+
+       def __init__(self, host, cmd, ret):
+
+               super(SshFailed, self).__init__(
+                       "Failed to run {} on {}: Exited with {}".format(
+                               cmd, host, ret
+                       )
+               )
+
+               self.m_ret = ret
+
+class RegTest(object):
+
+       def __init__(self):
+
+               self.m_parser = argparse.ArgumentParser(
+                       description = "Regression testing between different 
SuSEfirewall2 versions. This script can compare two RPM versions of 
SuSEfirewall2. It aims at interactive evaluation of the differences in rule 
sets.",
+               )
+
+               self.m_parser.add_argument(
+                       "--host",
+                       help = "The remote host to test on",
+                       required = True
+               )
+
+               self.m_parser.add_argument(
+                       "--rpm",
+                       help = "The new RPM with changes to compare against",
+                       required = True
+               )
+
+               self.m_parser.add_argument(
+                       "-f", "--force",
+                       help = "Avoid asking 'unnecessary' questions.",
+                       action = 'store_true'
+               )
+
+               self.m_sf2_label = "SuSEfirewall2"
+               self.m_is_systemd = None
+
+       def prepareHostDir(self):
+
+               self.m_host_dir = os.path.join(
+                       tempfile.gettempdir(),
+                       '.'.join(["sf2", self.m_args.host])
+               )
+
+               if os.path.exists(self.m_host_dir):
+
+                       if not self.m_args.force:
+                               self.ask(
+                                       "Test directory {} already exists. Do 
you want to delete it?".format(self.m_host_dir)
+                               )
+
+                       shutil.rmtree(self.m_host_dir)
+
+               os.makedirs(self.m_host_dir)
+               print("Using", self.m_host_dir, "for test data")
+
+       def isSystemD(self):
+               """Returns whether the remote host runs SystemD. Otherwise
+               it's sysv init."""
+
+               if self.m_is_systemd != None:
+                       return self.m_is_systemd
+
+               try:
+                       self.runRemote("pgrep systemd", silent = True)
+                       self.m_is_systemd = True
+               except SshFailed:
+                       self.m_is_systemd = False
+
+               return self.m_is_systemd
+
+       def isSysV(self):
+               return not self.isSystemD()
+
+       def ask(self, q):
+
+               print(q)
+
+               answer = None
+               while answer not in ("y", "n", "yes", "no"):
+                       print("(y/n)? ", end = '')
+                       sys.stdout.flush()
+                       answer = sys.stdin.readline()
+
+                       if not answer:
+                               print("Aborted by user")
+                               sys.exit(3)
+
+                       answer = answer.lower().strip()
+
+               if answer not in ("y", "yes"):
+                       print("Not continuing operation")
+                       sys.exit(3)
+
+       def interactiveWait(self, msg):
+
+               print(msg)
+               print("ENTER to continue")
+               sys.stdout.flush()
+               nothing = sys.stdin.readline()
+
+       def invokeDiff(self, old, new):
+
+               subprocess.call(
+                       [
+                               "/usr/bin/vimdiff",
+                               old,
+                               new
+                       ],
+                       shell = False,
+                       close_fds = True
+               )
+
+       def checkRemoteStatus(self, cmd, out):
+               """Checks the exist status of a remote command via the given
+               stdout stream."""
+               ret = out.channel.recv_exit_status()
+
+               if ret != 0:
+                       raise SshFailed(self.m_args.host, cmd, ret)
+
+       def runRemote(self, cmd, silent = False):
+
+               inp, out, err = self.m_client.exec_command(cmd)
+
+               # TODO: this is not exactly safe against large amounts of
+               # stderr appearing, because we're reading stdout first. This
+               # might thus block forever.
+               # paramiko's handling of I/O streams is quite strange, this is
+               # the simplest "working" solution I came up with for the
+               # moment. redirecting stderr to stdout would be a good
+               # solution.
+               for _file in out, err:
+                       self.readRemote(_file, silent = silent)
+
+               self.checkRemoteStatus(cmd, out)
+
+       def getRemoteOutput(self, cmd):
+
+               inp, out, err = self.m_client.exec_command(cmd)
+
+               # TODO: same as with runRemote()
+               ret = out.read()
+
+               self.readRemote(err)
+               self.checkRemoteStatus(cmd, out)
+
+               return ret.decode()
+
+       def readRemote(self, _file, silent = False):
+
+               while True:
+                       line = _file.readline()
+                       if not line:
+                               break
+
+                       if silent:
+                               continue
+                       print(self.m_args.host, ">> ", line.strip(), sep = '')
+
+       def revertSF2(self):
+               """Reverts SF2 on the target host to the last known stable
+               version via zypper."""
+
+               print("Installing clean {} on {}".format(
+                       self.m_sf2_label,
+                       self.m_args.host
+               ))
+               print()
+               self.runRemote(
+                       "/usr/bin/zypper --non-interactive in -f 
{}".format(self.m_sf2_label)
+               )
+               print()
+
+       def restartSF2(self):
+               """Restarts the firewall on the target host."""
+
+               self.m_last_sf2_restart = self.getRemoteDate()
+               if self.isSysV():
+                       self.m_last_sf2_logline = self.getRemoteOutput(
+                               "tail -n1 /var/log/messages"
+                       )
+               print("Restarting firewall on {}".format(self.m_sf2_label))
+               print()
+               if self.isSystemD():
+                       self.runRemote("systemctl restart {}.service".format(
+                               self.m_sf2_label
+                       ))
+               else:
+                       self.runRemote("/etc/init.d/{}_setup restart".format(
+                               self.m_sf2_label
+                       ))
+               print()
+
+       def connect(self):
+
+               try:
+                       print("Connecting to {} via 
SSH".format(self.m_args.host))
+                       self.m_client = paramiko.client.SSHClient()
+                       self.m_client.load_system_host_keys()
+                       # this would auto-add unknown hosts, rather don't use
+                       # it except for testing (the test, that is! ;)
+                       
#self.m_client.set_missing_host_key_policy(paramiko.WarningPolicy())
+                       self.m_client.connect(self.m_args.host, username="root")
+
+                       self.m_sftp = self.m_client.open_sftp()
+               except Exception as e:
+                       print("Connection to {} 
failed:".format(self.m_args.host), e)
+                       sys.exit(1)
+
+       def determineHostProps(self):
+
+               if self.isSystemD():
+                       print("Remote host uses SystemD")
+               else:
+                       print("Remote host uses SysV init")
+
+       def getCurrentVersion(self):
+               """Returns the current version of the installed SF2 on the
+               remote host."""
+
+               info = self.getRemoteOutput(
+                       "zypper info {}".format(self.m_sf2_label)
+               )
+
+               for line in info.splitlines():
+
+                       if not line.startswith("Version"):
+                               continue
+
+                       parts = line.split()
+                       # on SLE-12 this is "Version     : ...."
+                       # on SLE-11 this is "Version: ...."
+                       return parts[1] if parts[1] != ":" else parts[2]
+
+               raise Exception("Failed to determine currently installed SF2 
version2")
+
+       def fetchIptablesRules(self, target_dir):
+               """Fetches both, IPv4 and IPv6 table rules and saves them in
+               the current test directory."""
+               print("Fetching current iptables rules")
+               print()
+
+               for iptables in ("iptables", "ip6tables"):
+                       rules = self.getRemoteOutput("{} -S".format(iptables))
+                       outpath = os.path.join(target_dir, iptables + ".rules")
+
+                       print("Writing", outpath)
+                       with open(outpath, 'w') as out_fd:
+                               out_fd.write(rules)
+
+               print()
+
+       def uploadFile(self, which, whereto):
+
+               self.m_sftp.put(which, whereto)
+
+       def installNew(self):
+
+               print("Uploading rpm")
+               print()
+               base = os.path.basename(self.m_args.rpm)
+               rempath = os.path.join(tempfile.gettempdir(), base)
+               self.uploadFile(self.m_args.rpm, rempath)
+               print()
+
+               if not self.m_args.force:
+                       self.ask(
+                               "The rpm in {} will now be installed on {}. "
+                               "Continue?".format(
+                                       self.m_args.rpm,
+                                       self.m_args.host
+                       ))
+
+               print("Installing {} on remote host".format(base))
+
+               self.installRPM(rempath)
+
+               print()
+
+       def installRPM(self, rpm):
+               
+               # install RPMs directly via rpm is better than via zypper. the
+               # latter complains about signatures and such
+               self.runRemote("rpm -i --force --nodeps --replacepkgs 
{}".format(
+                       rpm
+               ))
+
+       def getRemoteDate(self):
+               """Returns the remote date as a datetime object."""
+
+               unixtime = self.getRemoteOutput("date +'%s'")
+
+               return datetime.datetime.fromtimestamp(float(unixtime))
+
+       def getSF2Log(self, target_dir):
+
+               if self.isSystemD():
+                       log = self.getRemoteOutput(
+                               "journalctl -u {}.service -S '{}'".format(
+                                       self.m_sf2_label,
+                                       self.m_last_sf2_restart.strftime(
+                                               "%Y-%m-%d %H:%M:%S"
+                                       )
+                               )
+                       )
+               else:
+                       parts = self.m_last_sf2_logline.split()
+                       date = ' '.join(parts[:3])
+                       log = self.getRemoteOutput(
+                               "sed -n '/^{}/,$p' /var/log/messages".format(
+                                       date
+                               )
+                       )
+
+               with open(os.path.join(target_dir, "log"), 'w') as log_fd:
+                       log_fd.write(log)
+
+       def showLogs(self, old_dir, new_dir):
+
+               self.interactiveWait("Showing diff of log output")
+
+               self.invokeDiff(
+                       os.path.join(old_dir, "log"),
+                       os.path.join(new_dir, "log")
+               )
+
+               for rules in ("iptables", "ip6tables"):
+                       self.interactiveWait(
+                               "Showing diff of {} rules".format(rules)
+                       )
+                       rule_file = "{}.rules".format(rules)
+                       self.invokeDiff(
+                               os.path.join(old_dir, rule_file),
+                               os.path.join(new_dir, rule_file)
+                       )
+
+       def run(self):
+
+               self.m_args = self.m_parser.parse_args()
+
+               self.prepareHostDir()
+               self.connect()
+               self.determineHostProps()
+
+               if not self.m_args.force:
+                       self.ask("The {sf2} on {host} will be (re-)installed 
and restarted. "
+                               "Do you want to continue?".format(
+                                       sf2 = self.m_sf2_label, host = 
self.m_args.host)
+                       )
+
+               self.revertSF2()
+               self.restartSF2()
+               first_version = self.getCurrentVersion()
+               first_version_dir = os.path.join(self.m_host_dir, first_version)
+               os.makedirs(first_version_dir)
+               os.symlink(
+                       first_version_dir,
+                       os.path.join(self.m_host_dir, "old")
+               )
+
+               self.fetchIptablesRules(first_version_dir)
+               self.getSF2Log(first_version_dir)
+
+               self.installNew()
+               self.restartSF2()
+               second_version = self.getCurrentVersion()
+               if first_version == second_version:
+                       second_version += "-new"
+               second_version_dir = os.path.join(self.m_host_dir, 
second_version)
+               os.makedirs(second_version_dir)
+               os.symlink(
+                       second_version_dir,
+                       os.path.join(self.m_host_dir, "new")
+               )
+               self.fetchIptablesRules(second_version_dir)
+               self.getSF2Log(second_version_dir)
+
+               # create a clean state again
+               self.revertSF2()
+
+               self.showLogs(first_version_dir, second_version_dir)
+
+               print("You can find logs in")
+               print("-", first_version_dir)
+               print("-", second_version_dir)
+
+regtest = RegTest()
+regtest.run()


Reply via email to