Merge pull request #185 from yarikoptic/_tent/jail.conf

"Debian-style" jail.conf -- lean and nice (Fixes #156) + more testing.
pull/190/merge
Yaroslav Halchenko 2013-04-24 12:10:18 -07:00
commit bddbf1e398
6 changed files with 418 additions and 179 deletions

View File

@ -1,22 +1,31 @@
# Fail2Ban jail specifications file
#
# WARNING: heavily refactored in 0.9.0 release. Please review and
# customize settings for your setup.
#
# Comments: use '#' for comment lines and ';' for inline comments
#
# Changes: in most of the cases you should not modify this
# file, but provide customizations in jail.local file, e.g.:
# file, but provide customizations in jail.local file,
# or separate .conf files under jail.d/ directory, e.g.:
#
# [DEFAULT]
# bantime = 3600
#
# [ssh-iptables]
# [sshd]
# enabled = true
#
# See jail.conf(5) man page for more information
# The DEFAULT allows a global definition of the options. They can be overridden
# in each jail afterwards.
[DEFAULT]
#
# MISCELLANEOUS OPTIONS
#
# "ignoreip" can be an IP address, a CIDR mask or a DNS host. Fail2ban will not
# ban a host which matches an address in this list. Several addresses can be
# defined using space separator.
@ -30,7 +39,7 @@ bantime = 600
findtime = 600
# "maxretry" is the number of failures before a host get banned.
maxretry = 3
maxretry = 5
# "backend" specifies the backend used to get files modification.
# Available options are "pyinotify", "gamin", "polling" and "auto".
@ -62,46 +71,122 @@ usedns = warn
# auto: will use the system locale setting
logencoding = auto
# "enabled" enables the jails.
# By default all jails are disabled, and it should stay this way.
# Enable only relevant to your setup jails in your .local or jail.d/*.conf
#
# true: jail will be enabled and log files will get monitored for changes
# false: jail is not enabled
enabled = false
# This jail corresponds to the standard configuration in Fail2ban 0.6.
# The mail-whois action send a notification e-mail with a whois request
# in the body.
[ssh-iptables]
# "filter" defines the filter to use by the jail.
# By default jails have names matching their filter name
#
filter = %(__name__)s
enabled = false
#
# ACTIONS
#
# Some options used for actions
# Destination email address used solely for the interpolations in
# jail.{conf,local} configuration files.
destemail = root@localhost
# E-mail action. Since 0.8.1 Fail2Ban uses sendmail MTA for the
# mailing. Change mta configuration parameter to mail if you want to
# revert to conventional 'mail'.
mta = sendmail
# Default protocol
protocol = tcp
# Specify chain where jumps would need to be added in iptables-* actions
chain = INPUT
# Ports to be banned
# Usually should be overridden in a particular jail
port = 0:65535
#
# Action shortcuts. To be used to define action parameter
# Default banning action (e.g. iptables, iptables-new,
# iptables-multiport, shorewall, etc) It is used to define
# action_* variables. Can be overridden globally or per
# section within jail.local file
banaction = iptables-multiport
# The simplest action to take: ban only
action_ = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
# ban & send an e-mail with whois report to the destemail.
action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
# ban & send an e-mail with whois report and relevant log lines
# to the destemail.
action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
# Choose default action. To change, just override value of 'action' with the
# interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local
# globally (section [DEFAULT]) or per specific section
action = %(action_)s
#
# JAILS
#
#
# SSH servers
#
[sshd]
port = ssh
logpath = /var/log/auth.log
/var/log/sshd.log
[sshd-ddos]
port = ssh
logpath = /var/log/auth.log
/var/log/sshd.log
[dropbear]
port = ssh
filter = sshd
action = iptables[name=SSH, port=ssh, protocol=tcp]
sendmail-whois[name=SSH, dest=you@example.com, sender=fail2ban@example.com]
logpath = /var/log/sshd.log
maxretry = 5
logpath = /var/log/dropbear
[proftpd-iptables]
enabled = false
filter = proftpd
action = iptables[name=ProFTPD, port=ftp, protocol=tcp]
sendmail-whois[name=ProFTPD, dest=you@example.com]
logpath = /var/log/proftpd/proftpd.log
maxretry = 6
# Generic filter for PAM. Has to be used with action which bans all
# ports such as iptables-allports, shorewall
# This jail forces the backend to "polling".
[pam-generic]
[sasl-iptables]
# pam-generic filter can be customized to monitor specific subset of 'tty's
banaction = iptables-allports
logpath = /var/log/auth.log
enabled = false
filter = sasl
backend = polling
action = iptables[name=sasl, port=smtp, protocol=tcp]
sendmail-whois[name=sasl, dest=you@example.com]
logpath = /var/log/mail.log
[xinetd-fail]
banaction = iptables-multiport-log
logpath = /var/log/daemon.log
maxretry = 2
# .. custom jails
# Here we use TCP-Wrappers instead of Netfilter/Iptables. "ignoreregex" is
# used to avoid banning the user "myuser".
[ssh-tcpwrapper]
[sshd-tcpwrapper]
enabled = false
filter = sshd
action = hostsdeny
sendmail-whois[name=SSH, dest=you@example.com]
@ -111,127 +196,74 @@ logpath = /var/log/sshd.log
# Here we use blackhole routes for not requiring any additional kernel support
# to store large volumes of banned IPs
[ssh-route]
[sshd-route]
enabled = false
filter = sshd
action = route
logpath = /var/log/sshd.log
maxretry = 5
# Here we use a combination of Netfilter/Iptables and IPsets
# for storing large volumes of banned IPs
#
# IPset comes in two versions. See ipset -V for which one to use
# requires the ipset package and kernel support.
[ssh-iptables-ipset4]
[sshd-iptables-ipset4]
enabled = false
filter = sshd
action = iptables-ipset-proto4[name=SSH, port=ssh, protocol=tcp]
logpath = /var/log/sshd.log
maxretry = 5
[ssh-iptables-ipset6]
enabled = false
[sshd-iptables-ipset6]
filter = sshd
action = iptables-ipset-proto6[name=SSH, port=ssh, protocol=tcp, bantime=600]
logpath = /var/log/sshd.log
maxretry = 5
# This jail demonstrates the use of wildcards in "logpath".
# Moreover, it is possible to give other files on a new line.
# This jail uses ipfw, the standard firewall on FreeBSD. The "ignoreip"
# option is overridden in this jail. Moreover, the action "mail-whois" defines
# the variable "name" which contains a comma using "". The characters '' are
# valid too.
[apache-tcpwrapper]
[sshd-ipfw]
enabled = false
filter = apache-auth
action = hostsdeny
filter = sshd
action = ipfw[localhost=192.168.0.1]
sendmail-whois[name="SSH,IPFW", dest=you@example.com]
logpath = /var/log/auth.log
ignoreip = 168.192.0.1
#
# HTTP servers
#
[apache-auth]
port = http,https
logpath = /var/log/apache*/*error.log
/home/www/myhomepage/error.log
maxretry = 6
# The hosts.deny path can be defined with the "file" argument if it is
# not in /etc.
[postfix-tcpwrapper]
enabled = false
filter = postfix
action = hostsdeny[file=/not/a/standard/path/hosts.deny]
sendmail[name=Postfix, dest=you@example.com]
logpath = /var/log/postfix.log
bantime = 300
# Do not ban anybody. Just report information about the remote host.
# A notification is sent at most every 600 seconds (bantime).
[vsftpd-notification]
enabled = false
filter = vsftpd
action = sendmail-whois[name=VSFTPD, dest=you@example.com]
logpath = /var/log/vsftpd.log
maxretry = 5
bantime = 1800
# Same as above but with banning the IP address.
[vsftpd-iptables]
enabled = false
filter = vsftpd
action = iptables[name=VSFTPD, port=ftp, protocol=tcp]
sendmail-whois[name=VSFTPD, dest=you@example.com]
logpath = /var/log/vsftpd.log
maxretry = 5
bantime = 1800
# Ban hosts which agent identifies spammer robots crawling the web
# for email addresses. The mail outputs are buffered.
[apache-badbots]
enabled = false
filter = apache-badbots
action = iptables-multiport[name=BadBots, port="http,https"]
sendmail-buffered[name=BadBots, lines=5, dest=you@example.com]
logpath = /var/www/*/logs/access_log
port = http,https
logpath = /var/log/apache*/*access.log
/var/www/*/logs/access_log
bantime = 172800
maxretry = 1
# Use shorewall instead of iptables.
[apache-noscript]
[apache-shorewall]
port = http,https
logpath = /var/log/apache*/*error.log
maxretry = 6
enabled = false
filter = apache-noscript
action = shorewall
sendmail[name=Postfix, dest=you@example.com]
logpath = /var/log/apache2/error_log
[apache-overflows]
# Monitor roundcube server
[roundcube-iptables]
enabled = false
filter = roundcube-auth
action = iptables[name=RoundCube, port="http,https"]
logpath = /var/log/roundcube/userlogins
# Monitor SOGo groupware server
[sogo-iptables]
enabled = false
filter = sogo-auth
port = http, https
# without proxy this would be:
# port = 20000
action = iptables[name=SOGo, port="http,https"]
logpath = /var/log/sogo/sogo.log
port = http,https
logpath = /var/log/apache*/*error.log
maxretry = 2
# Ban attackers that try to use PHP's URL-fopen() functionality
# through GET/POST variables. - Experimental, with more than a year
@ -239,53 +271,145 @@ logpath = /var/log/sogo/sogo.log
[php-url-fopen]
enabled = false
port = http,https
filter = php-url-fopen
logpath = /var/www/*/logs/access_log
maxretry = 1
# A simple PHP-fastcgi jail which works with lighttpd.
# If you run a lighttpd server, then you probably will
# find these kinds of messages in your error_log:
# ALERT tried to register forbidden variable GLOBALS
# through GET variables (attacker '1.2.3.4', file '/var/www/default/htdocs/index.php')
# This jail would block the IP 1.2.3.4.
# ALERT tried to register forbidden variable GLOBALS
# through GET variables (attacker '1.2.3.4', file '/var/www/default/htdocs/index.php')
[lighttpd-fastcgi]
enabled = false
port = http,https
filter = lighttpd-fastcgi
# adapt the following two items as needed
logpath = /var/log/lighttpd/error.log
maxretry = 2
# Same as above for mod_auth
# It catches wrong authentications
# It catches wrong authentifications
[lighttpd-auth]
enabled = false
port = http,https
filter = lighttpd-auth
# adapt the following two items as needed
logpath = /var/log/lighttpd/error.log
maxretry = 2
# This jail uses ipfw, the standard firewall on FreeBSD. The "ignoreip"
# option is overridden in this jail. Moreover, the action "mail-whois" defines
# the variable "name" which contains a comma using "". The characters '' are
# valid too.
[roundcube-auth]
[ssh-ipfw]
port = http,https
logpath = /var/log/roundcube/userlogins
enabled = false
filter = sshd
action = ipfw[localhost=192.168.0.1]
sendmail-whois[name="SSH,IPFW", dest=you@example.com]
[sogo-auth]
port = http,https
# without proxy this would be:
# port = 20000
logpath = /var/log/sogo/sogo.log
# ... custom jails
[apache-tcpwrapper]
filter = apache-auth
action = hostsdeny
logpath = /var/log/apache*/*error.log
maxretry = 6
#
# FTP servers
#
[proftpd]
port = ftp,ftp-data,ftps,ftps-data
logpath = /var/log/proftpd/proftpd.log
[pure-ftpd]
port = ftp,ftp-data,ftps,ftps-data
logpath = /var/log/auth.log
ignoreip = 168.192.0.1
maxretry = 6
[vsftpd]
port = ftp,ftp-data,ftps,ftps-data
logpath = /var/log/vsftpd.log
# or overwrite it in jails.local to be
# logpath = /var/log/auth.log
# if you want to rely on PAM failed login attempts
# vsftpd's failregex should match both of those formats
# Do not ban anybody. Just report information about the remote host.
# A notification is sent at most every 600 seconds (bantime).
[vsftpd-notification]
filter = vsftpd
action = sendmail-whois[name=VSFTPD, dest=you@example.com]
logpath = /var/log/vsftpd.log
maxretry = 5
bantime = 1800
[wuftpd]
port = ftp,ftp-data,ftps,ftps-data
logpath = /var/log/syslog
maxretry = 6
#
# Mail servers
#
[courier-smtp]
port = smtp,ssmtp
logpath = /var/log/mail.log
[postfix]
port = smtp,ssmtp
logpath = /var/log/mail.log
# The hosts.deny path can be defined with the "file" argument if it is
# not in /etc.
[postfix-tcpwrapper]
filter = postfix
action = hostsdeny[file=/not/a/standard/path/hosts.deny]
sendmail[name=Postfix, dest=you@example.com]
logpath = /var/log/postfix.log
bantime = 300
#
# Mail servers authenticators: might be used for smtp,ftp,imap servers, so
# all relevant ports get banned
#
[courier-auth]
port = smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s
logpath = /var/log/mail.log
[sasl]
port = smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s
# You might consider monitoring /var/log/mail.warn instead if you are
# running postfix since it would provide the same log lines at the
# "warn" level but overall at the smaller filesize.
logpath = /var/log/mail.log
[dovecot]
port = smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s
logpath = /var/log/mail.log
#
# DNS servers
#
# These jails block attacks against named (bind9). By default, logging is off
# with bind9 installation. You will need something like this:
@ -314,65 +438,55 @@ ignoreip = 168.192.0.1
#
# [named-refused-udp]
#
# enabled = false
# filter = named-refused
# action = iptables-multiport[name=Named, port="domain,953", protocol=udp]
# sendmail-whois[name=Named, dest=you@example.com]
# port = domain,953
# protocol = udp
# logpath = /var/log/named/security.log
# ignoreip = 168.192.0.1
# This jail blocks TCP traffic for DNS requests.
[named-refused-tcp]
[named-refused]
enabled = false
filter = named-refused
action = iptables-multiport[name=Named, port="domain,953", protocol=tcp]
sendmail-whois[name=Named, dest=you@example.com]
port = domain,953
logpath = /var/log/named/security.log
ignoreip = 168.192.0.1
#
# Miscelaneous
#
# Multiple jails, 1 per protocol, are necessary ATM:
# see https://github.com/fail2ban/fail2ban/issues/37
[asterisk-tcp]
enabled = false
filter = asterisk
action = iptables-multiport[name=asterisk-tcp, port="5060,5061", protocol=tcp]
sendmail-whois[name=Asterisk, dest=you@example.com, sender=fail2ban@example.com]
port = 5060,5061
protocol = tcp
logpath = /var/log/asterisk/messages
maxretry = 10
[asterisk-udp]
enabled = false
filter = asterisk
action = iptables-multiport[name=asterisk-udp, port="5060,5061", protocol=udp]
sendmail-whois[name=Asterisk, dest=you@example.com, sender=fail2ban@example.com]
port = 5060,5061
protocol = udp
logpath = /var/log/asterisk/messages
maxretry = 10
# To log wrong MySQL access attempts add to /etc/my.cnf:
# log-error=/var/log/mysqld.log
# log-warning = 2
[mysqld-iptables]
[mysqld-auth]
enabled = false
filter = mysqld-auth
action = iptables[name=mysql, port=3306, protocol=tcp]
sendmail-whois[name=MySQL, dest=root, sender=fail2ban@example.com]
port = 3306
logpath = /var/log/mysqld.log
maxretry = 5
[guacamole-iptables]
[guacamole]
enabled = false
filter = guacamole
action = iptables-multiport[name=Guacmole, port="http,https"]
sendmail-whois[name=Guacamole, dest=root, sender=fail2ban@example.com]
port = http,https
logpath = /var/log/tomcat*/catalina.out
maxretry = 5
# Jail for more extended banning of persistent abusers
# !!! WARNING !!!
@ -381,8 +495,6 @@ maxretry = 5
# an infinite loop constantly feeding itself with non-informative lines
[recidive]
enabled = false
filter = recidive
logpath = /var/log/fail2ban.log
action = iptables-allports[name=recidive]
sendmail-whois-lines[name=recidive, logpath=/var/log/fail2ban.log]

View File

@ -28,15 +28,45 @@ __copyright__ = 'Copyright (c) 2007 Yaroslav Halchenko'
__license__ = 'GPL'
import logging, os, sys
if sys.version_info >= (3,2): # pragma: no cover
# SafeConfigParser deprecitated from python 3.2 (renamed ConfigParser)
from configparser import ConfigParser as SafeConfigParser
# SafeConfigParser deprecated from Python 3.2 (renamed to ConfigParser)
from configparser import ConfigParser as SafeConfigParser, \
BasicInterpolation
# And interpolation of __name__ was simply removed, thus we need to
# decorate default interpolator to handle it
class BasicInterpolationWithName(BasicInterpolation):
"""Decorator to bring __name__ interpolation back.
Original handling of __name__ was removed because of
functional deficiencies: http://bugs.python.org/issue10489
commit v3.2a4-105-g61f2761
Author: Lukasz Langa <lukasz@langa.pl>
Date: Sun Nov 21 13:41:35 2010 +0000
Issue #10489: removed broken `__name__` support from configparser
But should be fine to reincarnate for our use case
"""
def _interpolate_some(self, parser, option, accum, rest, section, map,
depth):
if section and not (__name__ in map):
map = map.copy() # just to be safe
map['__name__'] = section
return super(BasicInterpolationWithName, self)._interpolate_some(
parser, option, accum, rest, section, map, depth)
else: # pragma: no cover
from ConfigParser import SafeConfigParser
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
__all__ = ['SafeConfigParserWithIncludes']
class SafeConfigParserWithIncludes(SafeConfigParser):
"""
Class adds functionality to SafeConfigParser to handle included
@ -68,6 +98,14 @@ after = 1.conf
SECTION_NAME = "INCLUDES"
if sys.version_info >= (3,2):
# overload constructor only for fancy new Python3's
def __init__(self, *args, **kwargs):
kwargs = kwargs.copy()
kwargs['interpolation'] = BasicInterpolationWithName()
super(SafeConfigParserWithIncludes, self).__init__(
*args, **kwargs)
#@staticmethod
def getIncludes(resource, seen = []):
"""

View File

@ -54,7 +54,13 @@ class JailReader(ConfigReader):
return self.__name
def read(self):
return ConfigReader.read(self, "jail")
out = ConfigReader.read(self, "jail")
# Before returning -- verify that requested section
# exists at all
if not (self.__name in self.sections()):
raise ValueError("Jail %r was not found among available"
% self.__name)
return out
def isEnabled(self):
return self.__force_enable or self.__opts["enabled"]

View File

@ -21,12 +21,13 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav Halchenko"
__license__ = "GPL"
import os, shutil, tempfile, unittest
import os, shutil, sys, tempfile, unittest
from fail2ban.client.configreader import ConfigReader
from fail2ban.client.jailreader import JailReader
from fail2ban.client.filterreader import FilterReader
from fail2ban.client.jailsreader import JailsReader
from fail2ban.client.actionreader import ActionReader
from fail2ban.client.configurator import Configurator
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
@ -46,7 +47,7 @@ class ConfigReaderTest(unittest.TestCase):
"""Call after every test case."""
shutil.rmtree(self.d)
def _write(self, fname, value):
def _write(self, fname, value=None, content=None):
# verify if we don't need to create .d directory
if os.path.sep in fname:
d = os.path.dirname(fname)
@ -54,10 +55,13 @@ class ConfigReaderTest(unittest.TestCase):
if not os.path.exists(d_):
os.makedirs(d_)
f = open("%s/%s" % (self.d, fname), "w")
f.write("""
if value is not None:
f.write("""
[section]
option = %s
""" % value)
""" % value)
if content is not None:
f.write(content)
f.close()
def _remove(self, fname):
@ -104,15 +108,41 @@ option = %s
self._remove("c.local")
self.assertEqual(self._getoption(), 1)
def testInterpolations(self):
self.assertFalse(self.c.read('i')) # nothing is there yet
self._write("i.conf", value=None, content="""
[DEFAULT]
b = a
zz = the%(__name__)s
[section]
y = 4%(b)s
e = 5${b}
z = %(__name__)s
[section2]
z = 3%(__name__)s
""")
self.assertTrue(self.c.read('i'))
self.assertEqual(self.c.sections(), ['section', 'section2'])
self.assertEqual(self.c.get('section', 'y'), '4a') # basic interpolation works
self.assertEqual(self.c.get('section', 'e'), '5${b}') # no extended interpolation
self.assertEqual(self.c.get('section', 'z'), 'section') # __name__ works
self.assertEqual(self.c.get('section', 'zz'), 'thesection') # __name__ works even 'delayed'
self.assertEqual(self.c.get('section2', 'z'), '3section2') # and differs per section ;)
class JailReaderTest(unittest.TestCase):
def testIncorrectJail(self):
jail = JailReader('XXXABSENTXXX', basedir=CONFIG_DIR)
self.assertRaises(ValueError, jail.read)
def testStockSSHJail(self):
jail = JailReader('ssh-iptables', basedir=CONFIG_DIR) # we are running tests from root project dir atm
jail = JailReader('sshd', basedir=CONFIG_DIR) # we are running tests from root project dir atm
self.assertTrue(jail.read())
self.assertTrue(jail.getOptions())
self.assertFalse(jail.isEnabled())
self.assertEqual(jail.getName(), 'ssh-iptables')
self.assertEqual(jail.getName(), 'sshd')
def testSplitOption(self):
action = "mail-whois[name=SSH]"
@ -179,6 +209,59 @@ class JailsReaderTest(unittest.TestCase):
# commands to communicate to the server
self.assertEqual(comm_commands, [])
allFilters = set()
# All jails must have filter and action set
# TODO: evolve into a parametric test
for jail in jails.sections():
filterName = jails.get(jail, 'filter')
allFilters.add(filterName)
self.assertTrue(len(filterName))
# moreover we must have a file for it
# and it must be readable as a Filter
filterReader = FilterReader(filterName, jail, {})
filterReader.setBaseDir(CONFIG_DIR)
self.assertTrue(filterReader.read()) # opens fine
filterReader.getOptions({}) # reads fine
# test if filter has failregex set
self.assertTrue(filterReader._opts.get('failregex', '').strip())
actions = jails.get(jail, 'action')
self.assertTrue(len(actions.strip()))
# somewhat duplicating here what is done in JailsReader if
# the jail is enabled
for act in actions.split('\n'):
actName, actOpt = JailReader.extractOptions(act)
self.assertTrue(len(actName))
self.assertTrue(isinstance(actOpt, dict))
if actName == 'iptables-multiport':
self.assertTrue('port' in actOpt)
actionReader = ActionReader(
actName, jail, {}, basedir=CONFIG_DIR)
self.assertTrue(actionReader.read())
actionReader.getOptions({}) # populate _opts
cmds = actionReader.convert()
self.assertTrue(len(cmds))
# all must have some actionban
self.assertTrue(actionReader._opts.get('actionban', '').strip())
# Verify that all filters found under config/ have a jail
def get_all_confs(d):
from glob import glob
return set(
os.path.basename(x.replace('.conf', ''))
for x in glob(os.path.join(CONFIG_DIR, d, '*.conf')))
# TODO: provide jails for some additional filters
# ['gssftpd', 'qmail', 'apache-nohome', 'exim', 'dropbear', 'webmin-auth', 'cyrus-imap', 'sieve']
# self.assertEqual(get_all_confs('filter.d').difference(allFilters),
# set(['common']))
def testReadStockJailConfForceEnabled(self):
# more of a smoke test to make sure that no obvious surprises
# on users' systems when enabling shipped jails
@ -191,7 +274,7 @@ class JailsReaderTest(unittest.TestCase):
self.assertTrue(len(comm_commands))
# and we know even some of them by heart
for j in ['ssh-iptables', 'recidive']:
for j in ['sshd', 'recidive']:
# by default we have 'auto' backend ATM
self.assertTrue(['add', j, 'auto'] in comm_commands)
# and warn on useDNS