diff --git a/ChangeLog b/ChangeLog index d088833c..fe4f4ebf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -31,7 +31,7 @@ ver. 0.8.11 (2013/XX/XXX) - loves-unittests Daniel Black * action.d/hostsdeny -- NOTE: new dependancy 'ed'. Switched to use 'ed' across all platforms to ensure permissions are the same before and after a ban - - closes gh-266 + closes gh-266. hostsdeny supports daemon_list now too. - New Features: Daniel Black & ykimon * filter.d/3proxy.conf -- filter added @@ -39,6 +39,8 @@ ver. 0.8.11 (2013/XX/XXX) - loves-unittests * filter.d/exim-spam.conf -- a splitout of exim's spam regexes with additions for greater control over filtering spam. * add date expression for apache-2.4 - milliseconds + Christophe Carles & Daniel Black + * filter.d/perdition.conf -- filter added - Enhancements: Daniel Black * filter.d/{asterisk,assp,dovecot,proftpd}.conf -- regex hardening diff --git a/README.Solaris b/README.Solaris index 86f56241..e41e3811 100644 --- a/README.Solaris +++ b/README.Solaris @@ -82,7 +82,7 @@ REQ: Create /etc/fail2ban/jail.local containing: enabled = true filter = sshd -action = hostsdeny +action = hostsdeny[daemon_list=sshd] sendmail-whois[name=SSH, dest=you@example.com] ignoreregex = for myuser from logpath = /var/adm/auth.log @@ -119,6 +119,4 @@ GOTCHAS AND FIXMES * Fail2ban adds lines like these to /etc/hosts.deny: - ALL: 1.2.3.4 - - wouldn't it be better to just block sshd? + sshd: 1.2.3.4 diff --git a/THANKS b/THANKS index 84403239..4010ea72 100644 --- a/THANKS +++ b/THANKS @@ -11,6 +11,7 @@ Axel Thimm Bill Heaton Carlos Alberto Lopez Perez Christian Rauch +Christophe Carles Christoph Haas Christos Psonis Daniel B. Cid diff --git a/client/fail2banreader.py b/client/fail2banreader.py index ada88084..0171b457 100644 --- a/client/fail2banreader.py +++ b/client/fail2banreader.py @@ -39,7 +39,7 @@ class Fail2banReader(ConfigReader): ConfigReader.read(self, "fail2ban") def getEarlyOptions(self): - opts = [["string", "socket", "/tmp/fail2ban.sock"], + opts = [["string", "socket", "/var/run/fail2ban/fail2ban.sock"], ["string", "pidfile", "/var/run/fail2ban/fail2ban.pid"]] return ConfigReader.getOptions(self, "Definition", opts) diff --git a/client/jailsreader.py b/client/jailsreader.py index 408a40bf..00c63e3c 100644 --- a/client/jailsreader.py +++ b/client/jailsreader.py @@ -18,7 +18,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Author: Cyril Jaquier -# +# __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" @@ -32,7 +32,7 @@ from jailreader import JailReader logSys = logging.getLogger("fail2ban.client.config") class JailsReader(ConfigReader): - + def __init__(self, force_enable=False, **kwargs): """ Parameters @@ -44,17 +44,25 @@ class JailsReader(ConfigReader): ConfigReader.__init__(self, **kwargs) self.__jails = list() self.__force_enable = force_enable - + def read(self): return ConfigReader.read(self, "jail") - - def getOptions(self, section = None): + + def getOptions(self, section=None): + """Reads configuration for jail(s) and adds enabled jails to __jails + """ opts = [] self.__opts = ConfigReader.getOptions(self, "Definition", opts) - if section: - # Get the options of a specific jail. - jail = JailReader(section, basedir=self.getBaseDir(), force_enable=self.__force_enable) + if section is None: + sections = self.sections() + else: + sections = [ section ] + + # Get the options of all jails. + for sec in sections: + jail = JailReader(sec, basedir=self.getBaseDir(), + force_enable=self.__force_enable) jail.read() ret = jail.getOptions() if ret: @@ -62,23 +70,10 @@ class JailsReader(ConfigReader): # We only add enabled jails self.__jails.append(jail) else: - logSys.error("Errors in jail '%s'. Skipping..." % section) + logSys.error("Errors in jail %r. Skipping..." % sec) return False - else: - # Get the options of all jails. - for sec in self.sections(): - jail = JailReader(sec, basedir=self.getBaseDir(), force_enable=self.__force_enable) - jail.read() - ret = jail.getOptions() - if ret: - if jail.isEnabled(): - # We only add enabled jails - self.__jails.append(jail) - else: - logSys.error("Errors in jail '" + sec + "'. Skipping...") - return False return True - + def convert(self, allow_no_files=False): """Convert read before __opts and jails to the commands stream @@ -99,6 +94,6 @@ class JailsReader(ConfigReader): # Start jails for jail in self.__jails: stream.append(["start", jail.getName()]) - + return stream - + diff --git a/config/action.d/dummy.conf b/config/action.d/dummy.conf index 20507c0b..dc4e1dbf 100644 --- a/config/action.d/dummy.conf +++ b/config/action.d/dummy.conf @@ -10,14 +10,14 @@ # Notes.: command executed once at the start of Fail2Ban. # Values: CMD # -actionstart = touch /tmp/fail2ban.dummy - printf %%b "\n" >> /tmp/fail2ban.dummy +actionstart = touch /var/run/fail2ban/fail2ban.dummy + printf %%b "\n" >> /var/run/fail2ban/fail2ban.dummy # Option: actionstop # Notes.: command executed once at the end of Fail2Ban # Values: CMD # -actionstop = rm -f /tmp/fail2ban.dummy +actionstop = rm -f /var/run/fail2ban/fail2ban.dummy # Option: actioncheck # Notes.: command executed once before each actionban command @@ -31,7 +31,7 @@ actioncheck = # Tags: See jail.conf(5) man page # Values: CMD # -actionban = printf %%b "+\n" >> /tmp/fail2ban.dummy +actionban = printf %%b "+\n" >> /var/run/fail2ban/fail2ban.dummy # Option: actionunban # Notes.: command executed when unbanning an IP. Take care that the @@ -39,7 +39,7 @@ actionban = printf %%b "+\n" >> /tmp/fail2ban.dummy # Tags: See jail.conf(5) man page # Values: CMD # -actionunban = printf %%b "-\n" >> /tmp/fail2ban.dummy +actionunban = printf %%b "-\n" >> /var/run/fail2ban/fail2ban.dummy [Init] diff --git a/config/action.d/hostsdeny.conf b/config/action.d/hostsdeny.conf index 36e34948..d74f498d 100644 --- a/config/action.d/hostsdeny.conf +++ b/config/action.d/hostsdeny.conf @@ -1,6 +1,7 @@ # Fail2Ban configuration file # # Author: Cyril Jaquier +# Edited for cross platform by: James Stout, Yaroslav Halchenko and Daniel Black # # @@ -31,7 +32,7 @@ actioncheck = # Values: CMD # actionban = IP= && - printf %%b "ALL: $IP\n" >> + printf %%b ": $IP\n" >> # Option: actionunban # Notes.: command executed when unbanning an IP. Take care that the @@ -39,7 +40,7 @@ actionban = IP= && # Tags: See jail.conf(5) man page # Values: CMD # -actionunban = echo "/ALL: $/
d
w
q" | ed +actionunban = echo "/^: $/
d
w
q" | ed [Init] @@ -48,3 +49,9 @@ actionunban = echo "/ALL: $/
d
w
q" | ed # Values: STR Default: /etc/hosts.deny # file = /etc/hosts.deny + +# Option: daemon_list +# Notes: The list of services that this action will deny. See the man page +# for hosts.deny/hosts_access. Default is all services. +# Values: STR Default: ALL +daemon_list = ALL diff --git a/config/filter.d/asterisk.conf b/config/filter.d/asterisk.conf index e4e5de5f..fef43693 100644 --- a/config/filter.d/asterisk.conf +++ b/config/filter.d/asterisk.conf @@ -30,7 +30,7 @@ failregex = ^%(log_prefix)s Registration from '[^']*' failed for '(:\d+)?' ^%(log_prefix)s Host failed to authenticate as '[^']*'$ ^%(log_prefix)s No registration for peer '[^']*' \(from \)$ ^%(log_prefix)s Host failed MD5 authentication for '[^']*' \([^)]+\)$ - ^%(log_prefix)s Failed to authenticate user [^@]+@\S*$ + ^%(log_prefix)s Failed to authenticate (user|device) [^@]+@\S*$ ^%(log_prefix)s (?:handle_request_subscribe: )?Sending fake auth rejection for (device|user) \d*>;tag=\w+\S*$ ^%(log_prefix)s SecurityEvent="(FailedACL|InvalidAccountID|ChallengeResponseFailed|InvalidPassword)",EventTV="[\d-]+",Severity="[\w]+",Service="[\w]+",EventVersion="\d+",AccountID="\d+",SessionID="0x[\da-f]+",LocalAddress="IPV[46]/(UD|TC)P/[\da-fA-F:.]+/\d+",RemoteAddress="IPV[46]/(UD|TC)P//\d+"(,Challenge="\w+",ReceivedChallenge="\w+")?(,ReceivedHash="[\da-f]+")?$ diff --git a/config/filter.d/dropbear.conf b/config/filter.d/dropbear.conf index c822d08c..350747c6 100644 --- a/config/filter.d/dropbear.conf +++ b/config/filter.d/dropbear.conf @@ -27,8 +27,9 @@ _daemon = dropbear # These match the unmodified dropbear messages. It isn't possible to # match the source of the 'exit before auth' messages from dropbear. # -failregex = ^%(__prefix_line)slogin attempt for nonexistent user ('.*' )?from :.*\s*$ - ^%(__prefix_line)sbad password attempt for .+ from :.*\s*$ +failregex = ^%(__prefix_line)s(L|l)ogin attempt for nonexistent user ('.*' )?from :.*\s*$ + ^%(__prefix_line)s(B|b)ad password attempt for .+ from :.*\s*$ + ^%(__prefix_line)sExit before auth \(user '.+', \d+ fails\): Max auth tries reached - user '.+' from :\d+\s*$ # The only line we need to match with the modified dropbear. diff --git a/config/filter.d/perdition.conf b/config/filter.d/perdition.conf new file mode 100644 index 00000000..7fdca14b --- /dev/null +++ b/config/filter.d/perdition.conf @@ -0,0 +1,16 @@ +# Fail2Ban configuration file +# +# Author: Christophe Carles and Daniel Black +# +# + +[INCLUDES] + +before = common.conf + +[Definition] + +_daemon=perdition.\S+ + +failregex = ^%(__prefix_line)sAuth: :\d+->(\d{1,3}\.){3}\d{1,3}:\d+ client-secure=\S+ authorisation_id=NONE authentication_id=".+" server="\S+" protocol=\S+ server-secure=\S+ status="failed: (local authentication failure|Re-Authentication Failure)"$ + ^%(__prefix_line)sFatal Error reading authentication information from client :\d+->(\d{1,3}\.){3}\d{1,3}:\d+: Exiting child$ diff --git a/config/jail.conf b/config/jail.conf index 640a5874..86c61911 100644 --- a/config/jail.conf +++ b/config/jail.conf @@ -103,7 +103,7 @@ logpath = /root/path/to/assp/logs/maillog.txt enabled = false filter = sshd -action = hostsdeny +action = hostsdeny[daemon_list=sshd] sendmail-whois[name=SSH, dest=you@example.com] ignoreregex = for myuser from logpath = /var/log/sshd.log @@ -409,3 +409,10 @@ enabled = false filter = exim-spam action = iptables-multiport[name=exim-spam,port="25,465,587"] logpath = /var/log/exim/mainlog + +[perdition] +enabled = false +filter = perdition +action = iptables-multiport[name=perdition,port="110,143,993,995"] +logpath = /var/log/maillog + diff --git a/fail2ban-regex b/fail2ban-regex index e19b1bc9..4c5a0a11 100755 --- a/fail2ban-regex +++ b/fail2ban-regex @@ -240,7 +240,7 @@ class Fail2banRegex(object): def process(self, test_lines): - for line in test_lines: + for line_no, line in enumerate(test_lines): if line.startswith('#') or not line.strip(): # skip comment and empty lines continue @@ -256,6 +256,9 @@ class Fail2banRegex(object): self._line_stats.missed_lines.append(line) self._line_stats.tested += 1 + if line_no % 10 == 0: + self._filter.dateDetector.sortTemplate() + def printLines(self, ltype): lstats = self._line_stats assert(len(lstats.missed_lines) == lstats.tested - (lstats.matched + lstats.ignored)) @@ -374,7 +377,7 @@ if __name__ == "__main__": try: hdlr = open(cmd_log) print "Use log file : %s" % cmd_log - test_lines = hdlr.readlines() + test_lines = hdlr # Iterable except IOError, e: print e sys.exit(-1) diff --git a/files/nagios/README b/files/nagios/README index 28e84495..2b855d83 100644 --- a/files/nagios/README +++ b/files/nagios/README @@ -35,7 +35,7 @@ HELP: /etc/init.d/fail2ban stop 2.) delete the socket if available -rm /tmp/fail2ban.sock +rm /var/run/fail2ban/fail2ban.sock 3.) start the Service /etc/init.d/fail2ban start diff --git a/server/datedetector.py b/server/datedetector.py index 83d69733..ab2dd174 100644 --- a/server/datedetector.py +++ b/server/datedetector.py @@ -157,7 +157,7 @@ class DateDetector: self._appendTemplate(template) # MySQL: 130322 11:46:11 template = DateStrptime() - template.setName("MonthDayYear Hour:Minute:Second") + template.setName("YearMonthDay Hour:Minute:Second") template.setRegex("^\d{2}\d{2}\d{2} +\d{1,2}:\d{2}:\d{2}") template.setPattern("%y%m%d %H:%M:%S") self._appendTemplate(template) diff --git a/server/datetemplate.py b/server/datetemplate.py index 86eeee8e..0754391b 100644 --- a/server/datetemplate.py +++ b/server/datetemplate.py @@ -62,6 +62,9 @@ class DateTemplate: def incHits(self): self.__hits += 1 + + def resetHits(self): + self.__hits = 0 def matchDate(self, line): dateMatch = self.__cRegex.search(line) diff --git a/server/ticket.py b/server/ticket.py index 8826f26b..e0b2cb2e 100644 --- a/server/ticket.py +++ b/server/ticket.py @@ -47,7 +47,7 @@ class Ticket: def __str__(self): return "%s: ip=%s time=%s #attempts=%d" % \ - (self.__class__, self.__ip, self.__time, self.__attempt) + (self.__class__.__name__.split('.')[-1], self.__ip, self.__time, self.__attempt) def setIP(self, value): @@ -59,12 +59,6 @@ class Ticket: def getIP(self): return self.__ip - def setFile(self, value): - self.__file = value - - def getFile(self): - return self.__file - def setTime(self, value): self.__time = value diff --git a/setup.py b/setup.py index 1b6268bf..b61ecce4 100755 --- a/setup.py +++ b/setup.py @@ -53,7 +53,8 @@ setup( packages = [ 'common', 'client', - 'server' + 'server', + 'testcases' ], data_files = [ ('/etc/fail2ban', diff --git a/testcases/clientreadertestcase.py b/testcases/clientreadertestcase.py index 695b3877..65c3bbc2 100644 --- a/testcases/clientreadertestcase.py +++ b/testcases/clientreadertestcase.py @@ -21,7 +21,7 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko" __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav Halchenko" __license__ = "GPL" -import os, shutil, tempfile, unittest +import os, tempfile, shutil, unittest from client.configreader import ConfigReader from client.jailreader import JailReader from client.jailsreader import JailsReader @@ -65,7 +65,14 @@ option = %s self._write('d.conf', 0) self.assertEqual(self._getoption('d'), 0) os.chmod(f, 0) - self.assertFalse(self.c.read('d')) # should not be readable BUT present + # fragile test and known to fail e.g. under Cygwin where permissions + # seems to be not enforced, thus condition + if not os.access(f, os.R_OK): + self.assertFalse(self.c.read('d')) # should not be readable BUT present + else: + # SkipTest introduced only in 2.7 thus can't yet use generally + # raise unittest.SkipTest("Skipping on %s -- access rights are not enforced" % platform) + pass def testOptionalDotDDir(self): @@ -126,6 +133,13 @@ class JailsReaderTest(unittest.TestCase): # commands to communicate to the server self.assertEqual(comm_commands, []) + # We should not "read" some bogus jail + old_comm_commands = comm_commands[:] # make a copy + self.assertFalse(jails.getOptions("BOGUS")) + # and there should be no side-effects + self.assertEqual(jails.convert(), old_comm_commands) + + def testReadStockJailConfForceEnabled(self): # more of a smoke test to make sure that no obvious surprises # on users' systems when enabling shipped jails diff --git a/testcases/datedetectortestcase.py b/testcases/datedetectortestcase.py index 8a838700..218abba9 100644 --- a/testcases/datedetectortestcase.py +++ b/testcases/datedetectortestcase.py @@ -24,7 +24,7 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import unittest +import unittest, calendar, datetime, re, pprint from server.datedetector import DateDetector from server.datetemplate import DateTemplate @@ -122,6 +122,45 @@ class DateDetectorTest(unittest.TestCase): self.__datedetector.getTime('2012/10/11 02:37:17 [error] 18434#0')[:6], m1) + def testDateDetectorTemplateOverlap(self): + patterns = [template.getPattern() + for template in self.__datedetector.getTemplates() + if hasattr(template, "getPattern")] + + year = 2008 # Leap year, 08 for %y can be confused with both %d and %m + def iterDates(year): + for month in xrange(1, 13): + for day in xrange(2, calendar.monthrange(year, month)[1]+1, 9): + for hour in xrange(0, 24, 6): + for minute in xrange(0, 60, 15): + for second in xrange(0, 60, 15): # Far enough? + yield datetime.datetime( + year, month, day, hour, minute, second) + + overlapedTemplates = set() + for date in iterDates(year): + for pattern in patterns: + datestr = date.strftime(pattern) + datestrs = set([ + datestr, + re.sub(r"(\s)0", r"\1 ", datestr), + re.sub(r"(\s)0", r"\1", datestr)]) + for template in self.__datedetector.getTemplates(): + template.resetHits() + for datestr in datestrs: + if template.matchDate(datestr): # or getDate? + template.incHits() + + matchedTemplates = [template + for template in self.__datedetector.getTemplates() + if template.getHits() > 0] + assert matchedTemplates != [] # Should match at least one + if len(matchedTemplates) > 1: + overlapedTemplates.add((pattern, tuple(sorted(template.getName() + for template in matchedTemplates)))) + if overlapedTemplates: + print "WARNING: The following date templates overlap:" + pprint.pprint(overlapedTemplates) # def testDefaultTempate(self): # self.__datedetector.setDefaultRegex("^\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}") diff --git a/testcases/failmanagertestcase.py b/testcases/failmanagertestcase.py index 1bfab339..bd34e25f 100644 --- a/testcases/failmanagertestcase.py +++ b/testcases/failmanagertestcase.py @@ -78,6 +78,20 @@ class AddFailure(unittest.TestCase): ticket = self.__failManager.toBan() self.assertEqual(ticket.getIP(), "193.168.0.128") self.assertTrue(isinstance(ticket.getIP(), str)) + + # finish with rudimentary tests of the ticket + # verify consistent str + ticket_str = str(ticket) + self.assertEqual( + ticket_str, + 'FailTicket: ip=193.168.0.128 time=1167605999.0 #attempts=5') + # and some get/set-ers otherwise not tested + ticket.setTime(1000002000.0) + self.assertEqual(ticket.getTime(), 1000002000.0) + # and str() adjusted correspondingly + self.assertEqual( + str(ticket), + 'FailTicket: ip=193.168.0.128 time=1000002000.0 #attempts=5') def testbanNOK(self): self.__failManager.setMaxRetry(10) diff --git a/testcases/files/logs/asterisk b/testcases/files/logs/asterisk index ec2fec7c..b2eb7738 100644 --- a/testcases/files/logs/asterisk +++ b/testcases/files/logs/asterisk @@ -1,4 +1,6 @@ # Sample log files for asterisk +# failJSON: { "time": "2013-07-25T07:26:43", "match": true , "host": "1.2.3.4" } +[2013-07-25 07:26:43] NOTICE[26015][C-000006b2] chan_sip.c: Failed to authenticate device 101;tag=deadbeef # failJSON: { "time": "2012-02-13T17:21:54", "match": true , "host": "1.2.3.4" } [2012-02-13 17:21:54] NOTICE[1638] chan_sip.c: Registration from '' failed for '1.2.3.4' - Wrong password # failJSON: { "time": "2012-02-13T17:18:22", "match": true , "host": "1.2.3.4" } diff --git a/testcases/files/logs/dropbear b/testcases/files/logs/dropbear index 139292d7..d8a4d4d3 100644 --- a/testcases/files/logs/dropbear +++ b/testcases/files/logs/dropbear @@ -7,3 +7,9 @@ Mar 24 15:25:51 buffalo1 dropbear[4092]: bad password attempt for 'root' from 19 # failJSON: { "time": "2005-02-11T15:23:17", "match": true , "host": "198.51.100.215" } Feb 11 15:23:17 dropbear[1252]: login attempt for nonexistent user from ::ffff:198.51.100.215:60495 +# failJSON: { "time": "2005-07-27T01:04:12", "match": true , "host": "1.2.3.4" } +Jul 27 01:04:12 fail2ban-test dropbear[1335]: Bad password attempt for 'root' from 1.2.3.4:60588 +# failJSON: { "time": "2005-07-27T01:04:22", "match": true , "host": "1.2.3.4" } +Jul 27 01:04:22 fail2ban-test dropbear[1335]: Exit before auth (user 'root', 10 fails): Max auth tries reached - user 'root' from 1.2.3.4:60588 +# failJSON: { "time": "2005-07-27T01:18:59", "match": true , "host": "1.2.3.4" } +Jul 27 01:18:59 fail2ban-test dropbear[1477]: Login attempt for nonexistent user from 1.2.3.4:60794 diff --git a/testcases/files/logs/perdition b/testcases/files/logs/perdition new file mode 100644 index 00000000..24848e6f --- /dev/null +++ b/testcases/files/logs/perdition @@ -0,0 +1,4 @@ +# failJSON: { "time": "2005-07-18T16:07:18", "match": true , "host": "192.168.8.100" } +Jul 18 16:07:18 ares perdition.imaps[3194]: Auth: 192.168.8.100:2274->193.48.191.9:993 client-secure=ssl authorisation_id=NONE authentication_id="carles" server="imap.biotoul.fr:993" protocol=IMAP4S server-secure=ssl status="failed: Re-Authentication Failure" +# failJSON: { "time": "2005-07-18T16:08:58", "match": true , "host": "192.168.8.100" } +Jul 18 16:08:58 ares perdition.imaps[3194]: Fatal Error reading authentication information from client 192.168.8.100:2274->193.48.191.9:993: Exiting child diff --git a/testcases/filtertestcase.py b/testcases/filtertestcase.py index b961d0dc..2061327a 100644 --- a/testcases/filtertestcase.py +++ b/testcases/filtertestcase.py @@ -83,7 +83,12 @@ def _assert_equal_entries(utest, found, output, count=None): utest.assertEqual(found_time, output_time) if len(output) > 3 and count is None: # match matches # do not check if custom count (e.g. going through them twice) - utest.assertEqual(repr(found[3]), repr(output[3])) + if os.linesep != '\n' or sys.platform.startswith('cygwin'): + # on those where text file lines end with '\r\n', remove '\r' + srepr = lambda x: repr(x).replace(r'\r', '') + else: + srepr = repr + utest.assertEqual(srepr(found[3]), srepr(output[3])) def _assert_correct_last_attempt(utest, filter_, output, count=None): """Additional helper to wrap most common test case diff --git a/testcases/servertestcase.py b/testcases/servertestcase.py index 07cc373c..0af8f920 100644 --- a/testcases/servertestcase.py +++ b/testcases/servertestcase.py @@ -24,7 +24,7 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import unittest, socket, time, tempfile, os +import unittest, socket, time, tempfile, os, sys from server.server import Server from server.jail import Jail from common.exceptions import UnknownJailException @@ -498,7 +498,8 @@ class TransmitterLogging(TransmitterBase): self.setGetTest("logtarget", "STDOUT") self.setGetTest("logtarget", "STDERR") - self.setGetTest("logtarget", "SYSLOG") + if sys.platform.lower().startswith('linux'): + self.setGetTest("logtarget", "SYSLOG") def testLogLevel(self): self.setGetTest("loglevel", "4", 4)