From d441d61a1e6d982d408823d807028c8233abbb59 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Sat, 15 Jun 2013 12:34:16 +1000 Subject: [PATCH 01/11] TST/ENH: Improve regex around exim rejected by local_scan now has test cases. Unrouteable address error messages now normalised after looking into exim code. --- config/filter.d/exim.conf | 7 ++++++- testcases/files/logs/exim | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/config/filter.d/exim.conf b/config/filter.d/exim.conf index d335c9fc..da975d61 100644 --- a/config/filter.d/exim.conf +++ b/config/filter.d/exim.conf @@ -13,7 +13,12 @@ # (?:::f{4,6}:)?(?P[\w\-.^_]+) # Values: TEXT # -failregex = ^ H=\S+ \(\S+\) \[\] sender verify fail for <\S+>: (?:rejected by local_scan|Unrouteable address)\s*$ + +# From exim source code: ./src/receive.c:add_host_info_for_log +host_info = H=\S+ (\(\S+\) )?\[\] (?:I=\[\S+\]:\d+ )?(?:U=\S+ )?(P=e?smtp )? + +failregex = ^ %(host_info)ssender verify fail for <\S+>: Unrouteable address\s*$ + ^ \S+ F=(?:<>|\S+@\S+) %(host_info)s(?:temporarily )?rejected by local_scan\(\): .{0,256}$ ^ login authenticator failed for (\S+ )?\(\S+\) \[\]: 535 Incorrect authentication data( \(set_id=.*\)|: \d+ Time\(s\))?\s*$ # Option: ignoreregex diff --git a/testcases/files/logs/exim b/testcases/files/logs/exim index d86b6455..d7f0e58b 100644 --- a/testcases/files/logs/exim +++ b/testcases/files/logs/exim @@ -4,3 +4,9 @@ 2013-06-12 03:57:58 login authenticator failed for (ylmf-pc) [120.196.140.45]: 535 Incorrect authentication data: 1 Time(s) 2013-06-12 13:18:11 login authenticator failed for (USER-KVI9FGS9KP) [101.66.165.86]: 535 Incorrect authentication data 2013-06-10 10:10:59 H=ufficioestampa.it (srv.ufficioestampa.it) [193.169.56.211] sender verify fail for : Unrouteable address +# http://forum.lissyara.su/viewtopic.php?f=20&t=2985 +2010-11-24 21:48:41 1PLKOW-00046U-EW F=wvhluo@droolindog.com H=93-143-146-237.adsl.net.t-com.hr (droolindog.com) [93.143.146.237] I=[10.10.10.32]:25 P=esmtp temporarily rejected by local_scan(): Temporary local problem +# http://us.generation-nt.com/answer/exim-spamassassin-2010-0-x64-help-204020461.html +2011-07-07 15:44:16 1QexIu-0006dj-PX F=XXXXXX@XXXXXXXXXXXX H=localhost (saf.bio.caltech.edu) [127.0.0.1] P=esmtp temporarily rejected by local_scan(): Local configuration error - local_scan() library failure/usr/lib/exim/sa-exim.so: cannot open shared object file: No such file or directory +# http://www.clues.ltd.uk/howto/debian-sa-fprot-HOWTO.html +2004-01-18 07:15:35 1Ai79e-0000Dq-8i F=uzwltcmwto24@melissacam.biz H=lsanca1-ar3-4-47-028-040.lsanca1.elnk.dsl.genuity.net [4.47.28.40] P=smtp rejected by local_scan(): Rejected: hits=7.5 required=5.0 trigger=5.0 From b8cfda68b8dfda32648db621cd256d334eca0365 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Sun, 16 Jun 2013 00:19:37 +1000 Subject: [PATCH 02/11] ENH: new exim filter regexs. Also note a begining PID in this format. Thanks to ftoppi for the log entries --- ChangeLog | 2 +- THANKS | 1 + config/filter.d/exim.conf | 13 +++++++++---- testcases/files/logs/exim | 8 ++++++++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index f0df7ddc..842932fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -19,7 +19,7 @@ ver. 0.8.11 (2013/XX/XXX) - wanna-be-released Daniel Black * filter.d/{asterisk,assp,dovecot,proftpd}.conf -- regex hardening and extra failure examples in sample logs - Daniel Black & Georgiy Mernov + Daniel Black & Georgiy Mernov & ftoppi * filter.d/exim.conf -- regex hardening and extra failure examples in sample logs diff --git a/THANKS b/THANKS index 47c3e999..f8b18daa 100644 --- a/THANKS +++ b/THANKS @@ -18,6 +18,7 @@ Daniel Black David Nutter Eric Gerbier Enrico Labedzki +ftoppi Georgiy Mernov Guillaume Delvit Hanno 'Rince' Wagner diff --git a/config/filter.d/exim.conf b/config/filter.d/exim.conf index da975d61..62184fbf 100644 --- a/config/filter.d/exim.conf +++ b/config/filter.d/exim.conf @@ -15,11 +15,16 @@ # # From exim source code: ./src/receive.c:add_host_info_for_log -host_info = H=\S+ (\(\S+\) )?\[\] (?:I=\[\S+\]:\d+ )?(?:U=\S+ )?(P=e?smtp )? +host_info = H=([\w.-]+ )?(\(\S+\) )?\[\](:\d+)? (?:I=\[\S+\]:\d+ )?(?:U=\S+ )?(P=e?smtp )? +pid = ( \[\d+\])? -failregex = ^ %(host_info)ssender verify fail for <\S+>: Unrouteable address\s*$ - ^ \S+ F=(?:<>|\S+@\S+) %(host_info)s(?:temporarily )?rejected by local_scan\(\): .{0,256}$ - ^ login authenticator failed for (\S+ )?\(\S+\) \[\]: 535 Incorrect authentication data( \(set_id=.*\)|: \d+ Time\(s\))?\s*$ +failregex = ^%(pid)s %(host_info)ssender verify fail for <\S+>: Unrouteable address\s*$ + ^%(pid)s \S+ F=(?:<>|\S+@\S+) %(host_info)s(?:temporarily )?rejected by local_scan\(\): .{0,256}$ + ^%(pid)s login authenticator failed for (\S+ )?\(\S+\) \[\]: 535 Incorrect authentication data( \(set_id=.*\)|: \d+ Time\(s\))?\s*$ + ^%(pid)s %(host_info)sF=(?:<>|[^@]+@\S+) rejected RCPT [^@]+@\S+: (rejected found in dnsbl \S+|relay not permitted)\s*$ + ^%(pid)s \S+ %(host_info)sF=(?:<>|[^@]+@\S+) rejected after DATA: This message contains a virus \(\S+\)\.\s*$ + ^%(pid)s SMTP protocol synchronization error \(.*\): rejected (connection from|"\S+") %(host_info)s(next )?input=".*"\s*$ + ^%(pid)s SMTP call from \S+ \[\](:\d+)? (I=\[\S+\]:\d+ )?dropped: too many nonmail commands \(last was "\S+"\)\s*$ # Option: ignoreregex # Notes.: regex to ignore. If this regex matches, the line is ignored. diff --git a/testcases/files/logs/exim b/testcases/files/logs/exim index d7f0e58b..ebcb9726 100644 --- a/testcases/files/logs/exim +++ b/testcases/files/logs/exim @@ -10,3 +10,11 @@ 2011-07-07 15:44:16 1QexIu-0006dj-PX F=XXXXXX@XXXXXXXXXXXX H=localhost (saf.bio.caltech.edu) [127.0.0.1] P=esmtp temporarily rejected by local_scan(): Local configuration error - local_scan() library failure/usr/lib/exim/sa-exim.so: cannot open shared object file: No such file or directory # http://www.clues.ltd.uk/howto/debian-sa-fprot-HOWTO.html 2004-01-18 07:15:35 1Ai79e-0000Dq-8i F=uzwltcmwto24@melissacam.biz H=lsanca1-ar3-4-47-028-040.lsanca1.elnk.dsl.genuity.net [4.47.28.40] P=smtp rejected by local_scan(): Rejected: hits=7.5 required=5.0 trigger=5.0 +# https://github.com/fail2ban/fail2ban/pull/251#issuecomment-19493875 +2013-06-15 11:19:33 [2249] H=([2.181.148.95]) [2.181.148.95]:52391 I=[1.2.3.4]:25 F=fantasizesg4@google.com rejected RCPT some@email.com: rejected found in dnsbl zen.spamhaus.org +2013-06-10 18:33:32 [10099] H=(yakult.com.tw) [202.132.70.178]:3755 I=[1.2.3.4]:25 F=menacedsj04@listserv.eurasia.org rejected RCPT dir@ml3.ru: relay not permitted +2013-06-09 10:21:28 [14127] 1UlasQ-0003fr-45 F=mcorporation4@aol.com H=(mail38.fssprus.ru) [46.254.240.82]:43671 I=[1.2.3.4]:25 P=esmtp rejected by local_scan(): Rejected +2013-06-15 11:20:36 [2516] 1Unmew-0000ea-SE H=egeftech.static.otenet.gr [83.235.177.148]:32706 I=[1.2.3.4]:25 F=auguriesvbd40@google.com rejected after DATA: This message contains a virus (Sanesecurity.Junk.39934.UNOFFICIAL). +2013-06-02 06:54:20 [13314] SMTP protocol synchronization error (input sent without waiting for greeting): rejected connection from H=[211.148.195.192]:25936 I=[1.2.3.4]:25 input="GET / HTTP/1.1\r\n\r\n" +2013-06-02 09:05:48 [18505] SMTP protocol synchronization error (next input sent too soon: pipelining was not advertised): rejected "RSET" H=ba77.mx83.fr [82.96.160.77]:58302 I=[1.2.3.4]:25 next input="QUIT\r\n" +2013-06-02 09:22:05 [19591] SMTP call from pc012-6201.spo.scu.edu.tw [163.14.21.161]:3767 I=[1.2.3.4]:25 dropped: too many nonmail commands (last was "RSET") From 25c3bbfc2fead08c54891f293f5522d61199a62e Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Sun, 16 Jun 2013 00:25:24 +1000 Subject: [PATCH 03/11] DOC: credits/blame to me for changes to exim --- config/filter.d/exim.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/filter.d/exim.conf b/config/filter.d/exim.conf index 62184fbf..252da07a 100644 --- a/config/filter.d/exim.conf +++ b/config/filter.d/exim.conf @@ -1,7 +1,7 @@ # Fail2Ban configuration file # # Author: Cyril Jaquier -# +# Daniel Black (rewrote with strong regexs) # [Definition] From 2974cac40cc7709909fcb11a510f164c88e7db46 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Wed, 19 Jun 2013 22:10:18 -0400 Subject: [PATCH 04/11] RF: log all logging output from fail2ban-client to stderr. Close #264 otherwise it 1. 'interferes' with meaninful output of the client 2. if ERROR is logged it better go to stderr and separating ERROR from other levels is not that transparent with python's logging --- ChangeLog | 3 ++- fail2ban-client | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index a6bc4e21..f2425d2f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24,7 +24,8 @@ ver. 0.8.11 (2013/XX/XXX) - wanna-be-released sample logs Yaroslav Halchenko * fail2ban-regex -- refactored to provide more details (missing and - ignored lines, control over logging, etc) while maintaining look&feel. + ignored lines, control over logging, etc) while maintaining look&feel + * fail2ban-client -- log to standard error ver. 0.8.10 (2013/06/12) - wanna-be-secure ----------- diff --git a/fail2ban-client b/fail2ban-client index de8519f4..57235d79 100755 --- a/fail2ban-client +++ b/fail2ban-client @@ -336,13 +336,13 @@ class Fail2banClient: logSys.setLevel(logging.INFO) else: logSys.setLevel(logging.DEBUG) - # Add the default logging handler - stdout = logging.StreamHandler(sys.stdout) + # Add the default logging handler to dump to stderr + logout = logging.StreamHandler(sys.stderr) # set a format which is simpler for console use formatter = logging.Formatter('%(levelname)-6s %(message)s') # tell the handler to use this format - stdout.setFormatter(formatter) - logSys.addHandler(stdout) + logout.setFormatter(formatter) + logSys.addHandler(logout) # Set the configuration path self.__configurator.setBaseDir(self.__conf["conf"]) From b6be8b8243273bbe6549a1f1057e8633e767c314 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Fri, 21 Jun 2013 11:09:16 -0400 Subject: [PATCH 05/11] ENH/RF: remove __readJailConfig in favor of __readConfig + catch/error exceptions while reading the configuration --- fail2ban-client | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/fail2ban-client b/fail2ban-client index 57235d79..be48a613 100755 --- a/fail2ban-client +++ b/fail2ban-client @@ -229,7 +229,7 @@ class Fail2banClient: elif len(cmd) == 2 and cmd[0] == "reload": if self.__ping(): jail = cmd[1] - ret = self.__readJailConfig(jail) + ret = self.__readConfig(jail) # Do not continue if configuration is not 100% valid if not ret: return False @@ -394,19 +394,18 @@ class Fail2banClient: return False return self.__processCommand(args) - def __readConfig(self): + def __readConfig(self, jail=None): # Read the configuration - self.__configurator.readAll() - ret = self.__configurator.getOptions() - self.__configurator.convertToProtocol() - self.__stream = self.__configurator.getConfigStream() - return ret - - def __readJailConfig(self, jail): - self.__configurator.readAll() - ret = self.__configurator.getOptions(jail) - self.__configurator.convertToProtocol() - self.__stream = self.__configurator.getConfigStream() + # TODO: get away from stew of return codes and exception + # handling -- handle via exceptions + try: + self.__configurator.readAll() + ret = self.__configurator.getOptions(jail) + self.__configurator.convertToProtocol() + self.__stream = self.__configurator.getConfigStream() + except Exception, e: + logSys.error("Failed during configuration: %s" % e) + ret = False return ret #@staticmethod From 27947407bc7910f0f50972113218ebc73c4a22c7 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Fri, 21 Jun 2013 11:08:27 -0400 Subject: [PATCH 06/11] ENH: raise an exception if not a single file was found for the jail. Close #63 --- client/jailreader.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/jailreader.py b/client/jailreader.py index f8757e26..ef444125 100644 --- a/client/jailreader.py +++ b/client/jailreader.py @@ -107,12 +107,17 @@ class JailReader(ConfigReader): stream = [] for opt in self.__opts: if opt == "logpath": + found_files = 0 for path in self.__opts[opt].split("\n"): pathList = glob.glob(path) if len(pathList) == 0: - logSys.error("No file found for " + path) + logSys.error("No file(s) found for glob %s" % path) for p in pathList: + found_files += 1 stream.append(["set", self.__name, "addlogpath", p]) + if not found_files: + raise ValueError( + "Have not found any log file for %s jail" % self.__name) elif opt == "backend": backend = self.__opts[opt] elif opt == "maxretry": From 61f81c6b2f17576e970967a918997af55bc2b829 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Fri, 21 Jun 2013 11:12:27 -0400 Subject: [PATCH 07/11] Changelog entries with close statements for recent changes --- ChangeLog | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index f2425d2f..0dd7a073 100644 --- a/ChangeLog +++ b/ChangeLog @@ -25,7 +25,9 @@ ver. 0.8.11 (2013/XX/XXX) - wanna-be-released Yaroslav Halchenko * fail2ban-regex -- refactored to provide more details (missing and ignored lines, control over logging, etc) while maintaining look&feel - * fail2ban-client -- log to standard error + * fail2ban-client -- log to standard error. Closes gh-264 + * Fail to configure if not a single log file was found for an + enabled jail. Closes gh-63 ver. 0.8.10 (2013/06/12) - wanna-be-secure ----------- From 057f0ad1357273f027b944e046d66e486c2f197f Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Fri, 21 Jun 2013 12:44:37 -0400 Subject: [PATCH 08/11] ENH: allow_no_files option for jail's convert to allow testing of stock jail.conf --- client/jailreader.py | 13 +++++++++++-- client/jailsreader.py | 13 +++++++++++-- testcases/clientreadertestcase.py | 2 +- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/client/jailreader.py b/client/jailreader.py index ef444125..1a2be432 100644 --- a/client/jailreader.py +++ b/client/jailreader.py @@ -103,7 +103,16 @@ class JailReader(ConfigReader): logSys.warn("No actions were defined for %s" % self.__name) return True - def convert(self): + def convert(self, allow_no_files=False): + """Convert read before __opts to the commands stream + + Parameters + ---------- + allow_missing : bool + Either to allow log files to be missing entirely. Primarily is + used for testing + """ + stream = [] for opt in self.__opts: if opt == "logpath": @@ -115,7 +124,7 @@ class JailReader(ConfigReader): for p in pathList: found_files += 1 stream.append(["set", self.__name, "addlogpath", p]) - if not found_files: + if not (found_files or allow_no_files): raise ValueError( "Have not found any log file for %s jail" % self.__name) elif opt == "backend": diff --git a/client/jailsreader.py b/client/jailsreader.py index 098b525d..408a40bf 100644 --- a/client/jailsreader.py +++ b/client/jailsreader.py @@ -79,14 +79,23 @@ class JailsReader(ConfigReader): return False return True - def convert(self): + def convert(self, allow_no_files=False): + """Convert read before __opts and jails to the commands stream + + Parameters + ---------- + allow_missing : bool + Either to allow log files to be missing entirely. Primarily is + used for testing + """ + stream = list() for opt in self.__opts: if opt == "": stream.append([]) # Convert jails for jail in self.__jails: - stream.extend(jail.convert()) + stream.extend(jail.convert(allow_no_files=allow_no_files)) # Start jails for jail in self.__jails: stream.append(["start", jail.getName()]) diff --git a/testcases/clientreadertestcase.py b/testcases/clientreadertestcase.py index a8c60bf8..948431b3 100644 --- a/testcases/clientreadertestcase.py +++ b/testcases/clientreadertestcase.py @@ -132,7 +132,7 @@ class JailsReaderTest(unittest.TestCase): jails = JailsReader(basedir='config', force_enable=True) # we are running tests from root project dir atm self.assertTrue(jails.read()) # opens fine self.assertTrue(jails.getOptions()) # reads fine - comm_commands = jails.convert() + comm_commands = jails.convert(allow_no_files=True) # by default we have lots of jails ;) self.assertTrue(len(comm_commands)) From 6d331bcbea049b31a146f2196aeb33bfdccbe30f Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Thu, 27 Jun 2013 11:43:27 -0400 Subject: [PATCH 09/11] BF: make colon after [daemon] optional. Close #267 --- ChangeLog | 3 ++- config/filter.d/common.conf | 2 +- testcases/files/logs/sshd | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index a3ac95ce..45c6f343 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,7 +11,8 @@ ver. 0.8.11 (2013/XX/XXX) - wanna-be-released ----------- - Fixes: - + Yaroslav Halchenko + * filter.d/common.conf -- make colon after [daemon] optional. Closes gh-267 - New Features: Daniel Black & ykimon * filter.d/3proxy.conf -- filter added diff --git a/config/filter.d/common.conf b/config/filter.d/common.conf index aafeb5ca..d44a6325 100644 --- a/config/filter.d/common.conf +++ b/config/filter.d/common.conf @@ -33,7 +33,7 @@ __daemon_extra_re = (?:\[ID \d+ \S+\]) # Combinations of daemon name and PID # EXAMPLES: sshd[31607], pop(pam_unix)[4920] -__daemon_combs_re = (?:%(__pid_re)s?:\s+%(__daemon_re)s|%(__daemon_re)s%(__pid_re)s?:) +__daemon_combs_re = (?:%(__pid_re)s?:\s+%(__daemon_re)s|%(__daemon_re)s%(__pid_re)s?:?) # Some messages have a kernel prefix with a timestamp # EXAMPLES: kernel: [769570.846956] diff --git a/testcases/files/logs/sshd b/testcases/files/logs/sshd index 5dab1606..1943fb37 100644 --- a/testcases/files/logs/sshd +++ b/testcases/files/logs/sshd @@ -46,3 +46,6 @@ Apr 29 15:53:38 Jamess-iMac.local sshd[47831]: error: PAM: Authentication error Apr 29 16:53:38 Jamess-iMac.local sshd[47831]: error: PAM: authentication error for james from 205.186.180.101 via 192.168.1.201 Apr 29 17:53:38 Jamess-iMac.local sshd[47831]: error: PAM: authentication error for james from 205.186.180.102 Apr 29 18:53:38 Jamess-iMac.local sshd[47831]: error: PAM: authentication error for james from 205.186.180.103 + +#11 https://github.com/fail2ban/fail2ban/issues/267 There might be no colon after [daemon] +Jun 25 23:53:34 [sshd] User root from 1.2.3.4 not allowed because not listed in AllowUsers From ec0680d73ad6eb8cc136ac5493be9a636b1ee519 Mon Sep 17 00:00:00 2001 From: Steven Hiscocks Date: Sat, 29 Jun 2013 19:17:22 +0100 Subject: [PATCH 10/11] BF: fail2ban-regex when using ignoreregex file with empty regex --- fail2ban-regex | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fail2ban-regex b/fail2ban-regex index 4f5ffd73..78716a43 100755 --- a/fail2ban-regex +++ b/fail2ban-regex @@ -183,8 +183,10 @@ class Fail2banRegex(object): reader.read(value) print "Use %11s file : %s" % (regex, value) # TODO: reuse functionality in client - regex_values = [RegexStat(m) - for m in reader.get("Definition", regex).split('\n')] + regex_values = [ + RegexStat(m) + for m in reader.get("Definition", regex).split('\n') + if m != ""] except NoSectionError: print "No [Definition] section in %s" % value return False From b670b5c792bcdd6d49e25a84b52799a86b2abcfe Mon Sep 17 00:00:00 2001 From: Steven Hiscocks Date: Sat, 29 Jun 2013 20:17:42 +0100 Subject: [PATCH 11/11] TST: Change depreciated assertEquals to assertEqual in some tests --- testcases/actiontestcase.py | 8 ++++---- testcases/clientreadertestcase.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/testcases/actiontestcase.py b/testcases/actiontestcase.py index 9a7776ac..1aa9f24e 100644 --- a/testcases/actiontestcase.py +++ b/testcases/actiontestcase.py @@ -69,11 +69,11 @@ class ExecuteAction(unittest.TestCase): self.assertFalse(Action.substituteRecursiveTags({'A': '', 'B': ''})) self.assertFalse(Action.substituteRecursiveTags({'A': '', 'B': '', 'C': ''})) # missing tags are ok - self.assertEquals(Action.substituteRecursiveTags({'A': ''}), {'A': ''}) - self.assertEquals(Action.substituteRecursiveTags({'A': ' ','X':'fun'}), {'A': ' fun', 'X':'fun'}) - self.assertEquals(Action.substituteRecursiveTags({'A': ' ', 'B': 'cool'}), {'A': ' cool', 'B': 'cool'}) + self.assertEqual(Action.substituteRecursiveTags({'A': ''}), {'A': ''}) + self.assertEqual(Action.substituteRecursiveTags({'A': ' ','X':'fun'}), {'A': ' fun', 'X':'fun'}) + self.assertEqual(Action.substituteRecursiveTags({'A': ' ', 'B': 'cool'}), {'A': ' cool', 'B': 'cool'}) # rest is just cool - self.assertEquals(Action.substituteRecursiveTags(aInfo), + self.assertEqual(Action.substituteRecursiveTags(aInfo), { 'HOST': "192.0.2.0", 'ABC': '123 192.0.2.0', 'xyz': '890 123 192.0.2.0', diff --git a/testcases/clientreadertestcase.py b/testcases/clientreadertestcase.py index 948431b3..695b3877 100644 --- a/testcases/clientreadertestcase.py +++ b/testcases/clientreadertestcase.py @@ -108,7 +108,7 @@ class JailReaderTest(unittest.TestCase): action = "mail-whois[name=SSH]" expected = ['mail-whois', {'name': 'SSH'}] result = JailReader.splitAction(action) - self.assertEquals(expected, result) + self.assertEqual(expected, result) class JailsReaderTest(unittest.TestCase):