diff --git a/conf/cron/local_clean_mail b/conf/cron/local_clean_mail new file mode 100644 index 00000000..20397e4a --- /dev/null +++ b/conf/cron/local_clean_mail @@ -0,0 +1,5 @@ +#!/bin/bash +# +doveadm expunge -A mailbox Trash savedbefore 120d +doveadm expunge -A mailbox Spam savedbefore 120d + diff --git a/conf/fail2ban/filter.d/nginx-badbots.conf b/conf/fail2ban/filter.d/nginx-badbots.conf new file mode 100644 index 00000000..12d4105b --- /dev/null +++ b/conf/fail2ban/filter.d/nginx-badbots.conf @@ -0,0 +1,24 @@ +# Fail2Ban configuration file +# +# Regexp to catch known spambots and software alike. Please verify +# that it is your intent to block IPs which were driven by +# above mentioned bots. + + +[Definition] + +badbotscustom = EmailCollector|WebEMailExtrac|TrackBack/1\.02|sogou music spider|(?:Mozilla/\d+\.\d+ )?Jorgee +badbots = Atomic_Email_Hunter/4\.0|atSpider/1\.0|autoemailspider|bwh3_user_agent|China Local Browse 2\.6|ContactBot/0\.2|ContentSmartz|DataCha0s/2\.0|DBrowse 1\.4b|DBrowse 1\.4d|Demo Bot DOT 16b|Demo Bot Z 16b|DSurf15a 01|DSurf15a 71|DSurf15a 81|DSurf15a VA|EBrowse 1\.4b|Educate Search VxB|EmailSiphon|EmailSpider|EmailWolf 1\.00|ESurf15a 15|ExtractorPro|Franklin Locator 1\.8|FSurf15a 01|Full Web Bot 0416B|Full Web Bot 0516B|Full Web Bot 2816B|Guestbook Auto Submitter|Industry Program 1\.0\.x|ISC Systems iRc Search 2\.1|IUPUI Research Bot v 1\.9a|LARBIN-EXPERIMENTAL \(efp@gmx\.net\)|LetsCrawl\.com/1\.0 \+http\://letscrawl\.com/|Lincoln State Web Browser|LMQueueBot/0\.2|LWP\:\:Simple/5\.803|Mac Finder 1\.0\.xx|MFC Foundation Class Library 4\.0|Microsoft URL Control - 6\.00\.8xxx|Missauga Locate 1\.0\.0|Missigua Locator 1\.9|Missouri College Browse|Mizzu Labs 2\.2|Mo College 1\.9|MVAClient|Mozilla/2\.0 \(compatible; NEWT ActiveX; Win32\)|Mozilla/3\.0 \(compatible; Indy Library\)|Mozilla/3\.0 \(compatible; scan4mail \(advanced version\) http\://www\.peterspages\.net/?scan4mail\)|Mozilla/4\.0 \(compatible; Advanced Email Extractor v2\.xx\)|Mozilla/4\.0 \(compatible; Iplexx Spider/1\.0 http\://www\.iplexx\.at\)|Mozilla/4\.0 \(compatible; MSIE 5\.0; Windows NT; DigExt; DTS Agent|Mozilla/4\.0 efp@gmx\.net|Mozilla/5\.0 \(Version\: xxxx Type\:xx\)|NameOfAgent \(CMS Spider\)|NASA Search 1\.0|Nsauditor/1\.x|PBrowse 1\.4b|PEval 1\.4b|Poirot|Port Huron Labs|Production Bot 0116B|Production Bot 2016B|Production Bot DOT 3016B|Program Shareware 1\.0\.2|PSurf15a 11|PSurf15a 51|PSurf15a VA|psycheclone|RSurf15a 41|RSurf15a 51|RSurf15a 81|searchbot admin@google\.com|ShablastBot 1\.0|snap\.com beta crawler v0|Snapbot/1\.0|Snapbot/1\.0 \(Snap Shots, \+http\://www\.snap\.com\)|sogou develop spider|Sogou Orion spider/3\.0\(\+http\://www\.sogou\.com/docs/help/webmasters\.htm#07\)|sogou spider|Sogou web spider/3\.0\(\+http\://www\.sogou\.com/docs/help/webmasters\.htm#07\)|sohu agent|SSurf15a 11 |TSurf15a 11|Under the Rainbow 2\.2|User-Agent\: Mozilla/4\.0 \(compatible; MSIE 6\.0; Windows NT 5\.1\)|VadixBot|WebVulnCrawl\.unknown/1\.0 libwww-perl/5\.803|Wells Search II|WEP Search 00 + +failregex = ^ -.*"(GET|POST|HEAD).*HTTP.*"(?:%(badbots)s|%(badbotscustom)s)"$ + +ignoreregex = + +datepattern = ^[^\[]*\[({DATE}) + {^LN-BEG} + +# DEV Notes: +# List of bad bots fetched from http://www.user-agents.org +# Generated on Thu Nov 7 14:23:35 PST 2013 by files/gen_badbots. +# +# Author: Yaroslav Halchenko diff --git a/conf/fail2ban/filter.d/webexploits.conf b/conf/fail2ban/filter.d/webexploits.conf new file mode 100644 index 00000000..ff5a101a --- /dev/null +++ b/conf/fail2ban/filter.d/webexploits.conf @@ -0,0 +1,237 @@ +# Fail2Ban Web Exploits Filter +# Author & Copyright: Mitchell Krog - mitchellkrog@gmail.com +# REPO: https://github.com/mitchellkrogza/Fail2Ban.WebExploits +# V0.1.27 +# Last Updated: Tue May 8 11:08:42 SAST 2018 + +[Definition] + + +failregex = ^ -.*(GET|POST|HEAD).*(/\.git/config) + ^ -.*(GET|POST).*/administrator/index\.php.*500 + ^ -.*(GET|POST|HEAD).*(/:8880/) + ^ -.*(GET|POST|HEAD).*(/1\.sql) + ^ -.*(GET|POST|HEAD).*(/addons/theme/stv1/_static/image/favicon\.ico) + ^ -.*(GET|POST|HEAD).*(/addons/theme/stv1/_static/ts2/layout\.css) + ^ -.*(GET|POST|HEAD).*(/addons/theme/stv2/_static/ts2/layout\.css) + ^ -.*(GET|POST|HEAD).*(/Admin/Common/HelpLinks\.xml) + ^ -.*(GET|POST|HEAD).*(/admin-console) + ^ -.*(GET|POST|HEAD).*(/admin/inc/xml\.xslt) + ^ -.*(GET|POST|HEAD).*(/administrator/components/com_xcloner-backupandrestore/index2\.php) + # ^ -.*(GET|POST|HEAD).*(/administrator/index\.php) + ^ -.*(GET|POST|HEAD).*(/administrator/manifests/files/joomla\.xml) + ^ -.*(GET|POST|HEAD).*(/admin/mysql2/index\.php) + ^ -.*(GET|POST|HEAD).*(/admin/mysql/index\.php) + ^ -.*(GET|POST|HEAD).*(/admin/phpMyAdmin/index\.php) + ^ -.*(GET|POST|HEAD).*(/admin/pma/index\.php) + ^ -.*(GET|POST|HEAD).*(/admin/PMA/index\.php) + ^ -.*(GET|POST|HEAD).*(/admin/SouthidcEditor/ButtonImage/standard/componentmenu\.gif) + ^ -.*(GET|POST|HEAD).*(/admin/SouthidcEditor/Dialog/dialog\.js) + ^ -.*(GET|POST|HEAD).*(/admin/SouthidcEditor/ewebeditor\.asp) + ^ -.*(GET|POST|HEAD).*(/API/DW/Dwplugin/SystemLabel/SiteConfig\.htm) + ^ -.*(GET|POST|HEAD).*(/API/DW/Dwplugin/TemplateManage/login_site\.htm) + ^ -.*(GET|POST|HEAD).*(/API/DW/Dwplugin/TemplateManage/manage_site\.htm) + ^ -.*(GET|POST|HEAD).*(/API/DW/Dwplugin/TemplateManage/save_template\.htm) + ^ -.*(GET|POST|HEAD).*(/API/DW/Dwplugin/ThirdPartyTags/SiteFactory\.xml) + ^ -.*(GET|POST|HEAD).*(/api/jsonws/invoke) + ^ -.*(GET|POST|HEAD).*(/app/home/skins/default/style\.css) + ^ -.*(GET|POST|HEAD).*(/app/js/source/wcmlib/WCMConstants\.js) + ^ -.*(GET|POST|HEAD).*(/apple-app-site-association) + ^ -.*(GET|POST|HEAD).*(/app/Tpl/fanwe_1/js/) + ^ -.*(GET|POST|HEAD).*(/app/etc/local\.xml) + ^ -.*(GET|POST|HEAD).*(/Autodiscover/Autodiscover\.xml) + ^ -.*(GET|POST|HEAD).*(/_asterisk/) + ^ -.*(GET|POST|HEAD).*(/backup\.sql) + ^ -.*(GET|POST|HEAD).*(/bencandy\.php) + ^ -.*(GET|POST|HEAD).*(/blog/administrator/index\.php) + ^ -.*(GET|POST|HEAD).*(/boaform/admin/formLogin) + ^ -.*(GET|POST|HEAD).*(/cardamom\.html) + ^ -.*(GET|POST|HEAD).*(/cgi-bin/php) + ^ -.*(GET|POST|HEAD).*(/cgi-bin/php5) + ^ -.*(GET|POST|HEAD).*(/cgi/common\.cgi) + ^ -.*(GET|POST|HEAD).*(/CGI/Execute) + ^ -.*(GET|POST|HEAD).*(/check\.proxyradar\.com/azenv\.php) + ^ -.*(GET|POST|HEAD).*(/ckeditor/ckfinder/ckfinder\.html) + ^ -.*(GET|POST|HEAD).*(/ckeditor/ckfinder/install\.txt) + ^ -.*(GET|POST|HEAD).*(/ckfinder/ckfinder\.html) + ^ -.*(GET|POST|HEAD).*(/ckfinder/install\.txt) + ^ -.*(GET|POST|HEAD).*(/ckupload\.php) + ^ -.*(GET|POST|HEAD).*(/claroline/phpMyAdmin/index\.php) + ^ -.*(GET|POST|HEAD).*(/clases\.gone\.php) + ^ -.*(GET|POST|HEAD).*(/cms/administrator) + ^ -.*(GET|POST|HEAD).*(/command\.php) + ^ -.*(GET|POST|HEAD).*(/components/com_adsmanager/js/fullnoconflict\.js) + ^ -.*(GET|POST|HEAD).*(/components/com_b2jcontact/css/b2jcontact\.css) + ^ -.*(GET|POST|HEAD).*(/components/com_b2jcontact/router\.php) + ^ -.*(GET|POST|HEAD).*(/components/com_foxcontact/js/jtext\.js) + ^ -.*(GET|POST|HEAD).*(/components/com_sexycontactform/assets/js/index\.html) + ^ -.*(GET|POST|HEAD).*(/console/) + ^ -.*(GET|POST|HEAD).*(/console/auth/reg_newuser\.jsp) + ^ -.*(GET|POST|HEAD).*(/console/include/not_login\.htm) + ^ -.*(GET|POST|HEAD).*(/console/js/CTRSRequestParam\.js) + ^ -.*(GET|POST|HEAD).*(/console/js/CWCMDialogHead\.js) + ^ -.*(GET|POST|HEAD).*(/customer/account/login/referer/) + ^ -.*(GET|POST|HEAD).*(/currentsetting\.htm) + ^ -.*(GET|POST|HEAD).*(/CuteSoft_Client/CuteEditor/Help/default\.htm) + ^ -.*(GET|POST|HEAD).*(/CuteSoft_Client/CuteEditor/ImageEditor/listfiles\.aspx) + ^ -.*(GET|POST|HEAD).*(/CuteSoft_Client/CuteEditor/Images/log\.gif) + ^ -.*(GET|POST|HEAD).*(/data/admin/ver\.txt) + ^ -.*(GET|POST|HEAD).*(/database\.sql) + ^ -.*(GET|POST|HEAD).*(/data\.sql) + ^ -.*(GET|POST|HEAD).*(/datacenter/downloadApp/showDownload\.do) + ^ -.*(GET|POST|HEAD).*(/db/) + ^ -.*(GET|POST|HEAD).*(/dbadmin/) + ^ -.*(GET|POST|HEAD).*(/dbadmin/index\.php) + ^ -.*(GET|POST|HEAD).*(/db_backup\.sql) + ^ -.*(GET|POST|HEAD).*(/dbdump\.sql) + ^ -.*(GET|POST|HEAD).*(/db\.sql) + ^ -.*(GET|POST|HEAD).*(/db/index\.php) + ^ -.*(GET|POST|HEAD).*(/dump\.sql) + ^ -.*(GET|POST|HEAD).*(/deptWebsiteAction\.do) + ^ -.*(GET|POST|HEAD).*(/eams/static/scripts/grade/course/input\.js) + ^ -.*(GET|POST|HEAD).*(/editor/js/fckeditorcode_ie\.js) + ^ -.*(GET|POST|HEAD).*(\.env\.dev\.local) + ^ -.*(GET|POST|HEAD).*(/\.env\.development\.local) + ^ -.*(GET|POST|HEAD).*(/\.env\.prod\.local) + ^ -.*(GET|POST|HEAD).*(/\.env\.production\.local) + ^ -.*(GET|POST|HEAD).*(/examples/file-manager\.html) + ^ -.*(GET|POST|HEAD).*(/getcfg\.php) + ^ -.*(GET|POST|HEAD).*(/get_password\.php) + ^ -.*(GET|POST|HEAD).*(/\.git/info/) + ^ -.*(GET|POST|HEAD).*(/Hello\.World) + ^ -.*(GET|POST|HEAD).*(/hndUnblock\.cgi) + ^ -.*(GET|POST|HEAD).*(/images/login9/login_33\.jpg) + ^ -.*(GET|POST|HEAD).*(/include/dialog/config\.php) + ^ -.*(GET|POST|HEAD).*(/include/install_ocx\.aspx) + ^ -.*(GET|POST|HEAD).*(/index\.action) + ^ -.*(GET|POST|HEAD).*(/ip_js\.php) + ^ -.*(GET|POST|HEAD).*(/issmall/) + ^ -.*(GET|POST|HEAD).*(/jenkins/script) + ^ -.*(GET|POST|HEAD).*(/jenkins/login) + ^ -.*(GET|POST|HEAD).*(/jm-ajax/upload_file/) + ^ -.*(GET|POST|HEAD).*(/jmx-console) + ^ -.*(GET|POST|HEAD).*(/js/tools\.js) + ^ -.*(GET|POST|HEAD).*(/letrokart.sql) + ^ -.*(GET|POST|HEAD).*(/libraries/sfn\.php) + ^ -.*(GET|POST|HEAD).*(/localhost\.sql) + ^ -.*(GET|POST|HEAD).*(login\.destroy\.session) + ^ -.*(GET|POST|HEAD).*(/login/Jeecms\.do) + ^ -.*(GET|POST|HEAD).*(/logo_img\.php) + ^ -.*(GET|POST|HEAD).*(/maintlogin\.jsp) + ^ -.*(GET|POST|HEAD).*(/manager/html) + ^ -.*(GET|POST|HEAD).*(/manager/status) + ^ -.*(GET|POST|HEAD).*(/magmi/conf/magmi\.ini) + ^ -.*(GET|POST|HEAD).*(/master/login\.aspx) + ^ -.*(GET|POST|HEAD).*(/media/com_hikashop/js/hikashop\.js) + ^ -.*(GET|POST|HEAD).*(/modules/attributewizardpro/config\.xml) + ^ -.*(GET|POST|HEAD).*(/modules/columnadverts/config\.xml) + ^ -.*(GET|POST|HEAD).*(/modules/fieldvmegamenu/config\.xml) + ^ -.*(GET|POST|HEAD).*(/modules/homepageadvertise2/config\.xml) + ^ -.*(GET|POST|HEAD).*(/modules/homepageadvertise/config\.xml) + ^ -.*(GET|POST|HEAD).*(/modules/mod_simplefileuploadv1\.3/elements/udd\.php) + ^ -.*(GET|POST|HEAD).*(/modules/pk_flexmenu/config\.xml) + ^ -.*(GET|POST|HEAD).*(/modules/pk_vertflexmenu/config\.xml) + ^ -.*(GET|POST|HEAD).*(/modules/wdoptionpanel/config\.xml) + ^ -.*(GET|POST|HEAD).*(/msd) + ^ -.*(GET|POST|HEAD).*(/msd1\.24\.4) + ^ -.*(GET|POST|HEAD).*(/msd1\.24stable) + ^ -.*(GET|POST|HEAD).*(mstshash=NCRACK_USER) + ^ -.*(GET|POST|HEAD).*(/muieblackcat) + ^ -.*(GET|POST|HEAD).*(/myadmin2/index\.php) + ^ -.*(GET|POST|HEAD).*(/myadmin/index\.php) + ^ -.*(GET|POST|HEAD).*(/myadmin/scripts/setup\.php) + ^ -.*(GET|POST|HEAD).*(/MyAdmin/scripts/setup\.php) + ^ -.*(GET|POST|HEAD).*(/mysql-admin/index\.php) + ^ -.*(GET|POST|HEAD).*(/mysqladmin/index\.php) + ^ -.*(GET|POST|HEAD).*(/mysqldumper) + ^ -.*(GET|POST|HEAD).*(/mySqlDumper) + ^ -.*(GET|POST|HEAD).*(/MySQLDumper) + ^ -.*(GET|POST|HEAD).*(/mysqldump\.sql) + ^ -.*(GET|POST|HEAD).*(/mysql\.sql) + ^ -.*(GET|POST|HEAD).*(/phpadmin/index\.php) + ^ -.*(GET|POST|HEAD).*(/phpma/index\.php) + ^ -.*(GET|POST|HEAD).*(/phpMyadmin_bak/index\.php) + ^ -.*(GET|POST|HEAD).*(/phpMyAdmin/index\.php) + ^ -.*(GET|POST|HEAD).*(/phpMyAdmin/phpMyAdmin/index\.php) + ^ -.*(GET|POST|HEAD).*(/phpMyAdmin/scripts/setup\.php) + ^ -.*(GET|POST|HEAD).*(/plugins/anchor/anchor\.js) + ^ -.*(GET|POST|HEAD).*(/plugins/filemanager/filemanager/js) + ^ -.*(GET|POST|HEAD).*(/plus/download\.php) + ^ -.*(GET|POST|HEAD).*(/plus/heightsearch\.php) + ^ -.*(GET|POST|HEAD).*(/plus/rssmap\.html) + ^ -.*(GET|POST|HEAD).*(/plus/sitemap\.html) + ^ -.*(GET|POST|HEAD).*(/pma/) + ^ -.*(GET|POST|HEAD).*(/PMA/) + ^ -.*(GET|POST|HEAD).*(/PMA2/index\.php) + ^ -.*(GET|POST|HEAD).*(/pma/index\.php) + ^ -.*(GET|POST|HEAD).*(/PMA/index\.php) + ^ -.*(GET|POST|HEAD).*(/pmamy2/index\.php) + ^ -.*(GET|POST|HEAD).*(/pmamy/index\.php) + ^ -.*(GET|POST|HEAD).*(/pma-old/index\.php) + ^ -.*(GET|POST|HEAD).*(/pma/scripts/setup\.php) + ^ -.*(GET|POST|HEAD).*(/pmd/index\.php) + ^ -.*(GET|POST|HEAD).*(/privacy\.txt) + ^ -.*(GET|POST|HEAD).*(/resources/style/images/login/btn\.png) + ^ -.*(GET|POST|HEAD).*(/Scripts/jquery/maticsoft\.jquery\.min\.js) + ^ -.*(GET|POST|HEAD).*(/script/valid_formdata\.js) + ^ -.*(GET|POST|HEAD).*(/siteserver/login\.aspx) + ^ -.*(GET|POST|HEAD).*(/siteserver/upgrade/default\.aspx) + ^ -.*(GET|POST|HEAD).*(/site\.sql) + ^ -.*(GET|POST|HEAD).*(/sql\.sql) + ^ -.*(GET|POST|HEAD).*(soap:Envelope) + ^ -.*(GET|POST|HEAD).*(/solr/admin/info/system) + ^ -.*(GET|POST|HEAD).*(/stalker_portal/c) + ^ -.*(GET|POST|HEAD).*(/stalker_portal/server/adm/tv-channels/iptv-list-json) + ^ -.*(GET|POST|HEAD).*(/stalker_portal/server/adm/users/users-list-json) + ^ -.*(GET|POST|HEAD).*(/stssys\.htm) + ^ -.*(GET|POST|HEAD).*(/sys\.cache\.php) + ^ -.*(GET|POST|HEAD).*(/system/assets/jquery/jquery-2\.x\.min\.js) + ^ -.*(GET|POST|HEAD).*(/system_api\.php) + ^ -.*(GET|POST|HEAD).*(/template/1/bluewise/_files/jspxcms\.css) + ^ -.*(GET|POST|HEAD).*(/templates/jsn_glass_pro/ext/hikashop/jsn_ext_hikashop\.css) + ^ -.*(GET|POST|HEAD).*(/test_404_page/) + ^ -.*(GET|POST|HEAD).*(/test_for_404/) + ^ -.*(GET|POST|HEAD).*(/temp\.sql) + ^ -.*(GET|POST|HEAD).*(/translate\.sql) + ^ -.*(GET|POST|HEAD).*(Test Wuz Here) + ^ -.*(GET|POST|HEAD).*(/tmUnblock\.cgi) + ^ -.*(GET|POST|HEAD).*(/tools/phpMyAdmin/index\.ph) + ^ -.*(GET|POST|HEAD).*(/uc_server/control/admin/db\.php) + ^ -.*(GET|POST|HEAD).*(/upload/bank-icons/) + ^ -.*(GET|POST|HEAD).*(/UserCenter/css/admin/bgimg/admin_all_bg\.png) + ^ -.*(GET|POST|HEAD).*(/\.user\.ini) + ^ -.*(GET|POST|HEAD).*(\.bitcoin) + ^ -.*(GET|POST|HEAD).*(wallet\.dat) + ^ -.*(GET|POST|HEAD).*(bitcoin\.dat) + ^ -.*(GET|POST|HEAD).*(/magento2/admin) + ^ -.*(GET|POST|HEAD).*(/user/register?element_parents=account) + ^ -.*(GET|POST|HEAD).*(/user/themes/antimatter/js/antimatter\.js) + ^ -.*(GET|POST|HEAD).*(/user/themes/antimatter/js/modernizr\.custom\.71422\.js) + ^ -.*(GET|POST|HEAD).*(/user/themes/antimatter/js/slidebars\.min\.js) + ^ -.*(GET|POST|HEAD).*(/users\.sql) + ^ -.*(GET|POST|HEAD).*(/vendor/phpunit/phpunit) + ^ -.*(GET|POST|HEAD).*(/w00tw00t) + ^ -.*(GET|POST|HEAD).*(/webbuilder/script/locale/wb-lang-zh_CN\.js) + ^ -.*(GET|POST|HEAD).*(/web-console) + ^ -.*(GET|POST|HEAD).*(/webdav) + ^ -.*(GET|POST|HEAD).*(/web/phpMyAdmin/index\.php) + ^ -.*(GET|POST|HEAD).*(/whir_system/login\.aspx) + ^ -.*(GET|POST|HEAD).*(/whir_system/module/security/login\.aspx) + ^ -.*(GET|POST|HEAD).*(/wls-wsat/CoordinatorPortType) + ^ -.*(GET|POST|HEAD).*(/wpbase/url\.php) + ^ -.*(GET|POST|HEAD).*(/wp-content/plugins/) + ^ -.*(GET|POST|HEAD).*(/wp-content/uploads/dump\.sql) + ^ -.*(GET|POST|HEAD).*(/wp-includes/wlwmanifest\.xml) + ^ -.*(GET|POST|HEAD).*(/wp-login\.php) + ^ -.*(GET|POST|HEAD).*(/www/phpMyAdmin/index\.php) + ^ -.*(GET|POST|HEAD).*(\x00Cookie:) + ^ -.*(GET|POST|HEAD).*(\x22cache_name_function) + ^ -.*(GET|POST|HEAD).*(\x22JDatabaseDriverMysqli) + ^ -.*(GET|POST|HEAD).*(\x22JSimplepieFactory) + ^ -.*(GET|POST|HEAD).*(\x22sanitize) + ^ -.*(GET|POST|HEAD).*(\x22SimplePie) + ^ -.*(GET|POST|HEAD).*(\x5C0disconnectHandlers) + ^ -.*(GET).*(\.\./wp-config.php) + + +ignoreregex = diff --git a/conf/fail2ban/jail.d/geoipblock.conf b/conf/fail2ban/jail.d/geoipblock.conf new file mode 100644 index 00000000..c83c1023 --- /dev/null +++ b/conf/fail2ban/jail.d/geoipblock.conf @@ -0,0 +1,17 @@ +[geoipblocknginx] +enabled = true +port = http,https +filter = nginx-geoipblock +logpath = /var/log/nginx/geoipblock.log +maxretry = 1 +findtime = 120m +bantime = 15m + +[geoipblockssh] +enabled = true +port = ssh +filter = ssh-geoipblock +logpath = /var/log/syslog +maxretry = 1 +findtime = 120m +bantime = 15m diff --git a/conf/fail2ban/jail.d/webexploits.conf b/conf/fail2ban/jail.d/webexploits.conf new file mode 100644 index 00000000..30baaceb --- /dev/null +++ b/conf/fail2ban/jail.d/webexploits.conf @@ -0,0 +1,8 @@ +[webexploits] +enabled = true +port = http,https +filter = webexploits +logpath = /var/log/nginx/access.log +maxretry = 2 +findtime = 240m +bantime = 60m diff --git a/conf/fail2ban/jails.conf b/conf/fail2ban/jails.conf index 5de4fd48..0cf96751 100644 --- a/conf/fail2ban/jails.conf +++ b/conf/fail2ban/jails.conf @@ -5,13 +5,16 @@ # Whitelist our own IP addresses. 127.0.0.1/8 is the default. But our status checks # ping services over the public interface so we should whitelist that address of # ours too. The string is substituted during installation. -ignoreip = 127.0.0.1/8 PUBLIC_IP +ignoreip = 127.0.0.1/8 PUBLIC_IP ADMIN_HOME_IP +bantime = 15m +findtime = 120m +maxretry = 4 [dovecot] enabled = true filter = dovecotimap logpath = /var/log/mail.log -findtime = 30 +findtime = 2m maxretry = 20 [miab-management] @@ -20,7 +23,7 @@ filter = miab-management-daemon port = http,https logpath = /var/log/syslog maxretry = 20 -findtime = 30 +findtime = 15m [miab-munin] enabled = true @@ -28,7 +31,7 @@ port = http,https filter = miab-munin logpath = /var/log/nginx/access.log maxretry = 20 -findtime = 30 +findtime = 15m [miab-owncloud] enabled = true @@ -36,7 +39,7 @@ port = http,https filter = miab-owncloud logpath = STORAGE_ROOT/owncloud/nextcloud.log maxretry = 20 -findtime = 120 +findtime = 15m [miab-postfix587] enabled = true @@ -44,7 +47,7 @@ port = 587 filter = miab-postfix-submission logpath = /var/log/mail.log maxretry = 20 -findtime = 30 +findtime = 2m [miab-roundcube] enabled = true @@ -52,11 +55,13 @@ port = http,https filter = miab-roundcube logpath = /var/log/roundcubemail/errors.log maxretry = 20 -findtime = 30 +findtime = 15m [recidive] enabled = true maxretry = 10 +bantime = 2w +findtime = 3d action = iptables-allports[name=recidive] # In the recidive section of jail.conf the action contains: # @@ -74,5 +79,8 @@ enabled = true [sshd] enabled = true -maxretry = 7 +maxretry = 4 bantime = 3600 +mode = aggressive + + diff --git a/conf/nginx-webonlydomains.conf b/conf/nginx-webonlydomains.conf new file mode 100644 index 00000000..68c02a32 --- /dev/null +++ b/conf/nginx-webonlydomains.conf @@ -0,0 +1,28 @@ + # Expose this directory as static files. + root $ROOT; + index index.html index.htm; + + location = /robots.txt { + log_not_found off; + access_log off; + } + + location = /favicon.ico { + log_not_found off; + access_log off; + } + + # ADDITIONAL DIRECTIVES HERE + + # Disable viewing dotfiles (.htaccess, .svn, .git, etc.) + # This block is placed at the end. Nginx's precedence rules means this block + # takes precedence over all non-regex matches and only regex matches that + # come after it (i.e. none of those, since this is the last one.) That means + # we're blocking dotfiles in the static hosted sites but not the FastCGI- + # handled locations for Nextcloud (which serves user-uploaded files that might + # have this pattern, see #414) or some of the other services. + location ~ /\.(ht|svn|git|hg|bzr) { + log_not_found off; + access_log off; + deny all; + } diff --git a/management/backup.py b/management/backup.py index f5773cab..b23d1532 100755 --- a/management/backup.py +++ b/management/backup.py @@ -325,15 +325,6 @@ def perform_backup(full_backup, user_initiated=False): if get_target_type(config) == 'file': shell('check_call', ["/bin/chown", "-R", env["STORAGE_USER"], backup_dir]) - # Execute a post-backup script that does the copying to a remote server. - # Run as the STORAGE_USER user, not as root. Pass our settings in - # environment variables so the script has access to STORAGE_ROOT. - post_script = os.path.join(backup_root, 'after-backup') - if os.path.exists(post_script): - shell('check_call', - ['su', env['STORAGE_USER'], '-c', post_script, config["target"]], - env=env) - # Our nightly cron job executes system status checks immediately after this # backup. Since it checks that dovecot and postfix are running, block for a # bit (maximum of 10 seconds each) to give each a chance to finish restarting @@ -346,6 +337,16 @@ def perform_backup(full_backup, user_initiated=False): wait_for_service(25, True, env, 10) wait_for_service(993, True, env, 10) + # Execute a post-backup script that does the copying to a remote server. + # Run as the STORAGE_USER user, not as root. Pass our settings in + # environment variables so the script has access to STORAGE_ROOT. + post_script = os.path.join(backup_root, 'after-backup') + if os.path.exists(post_script): + shell('check_call', + ['su', env['STORAGE_USER'], '-c', post_script, config["target"]], + env=env) + + def run_duplicity_verification(): env = load_environment() backup_root = os.path.join(env["STORAGE_ROOT"], 'backup') diff --git a/management/mfa.py b/management/mfa.py index 32eb5183..0de4d858 100644 --- a/management/mfa.py +++ b/management/mfa.py @@ -109,7 +109,15 @@ def validate_auth_mfa(email, request, env): # If no MFA modes are added, return True. if len(mfa_state) == 0: return (True, []) - + + # munin routes are proxied by our control panel. We do not have + # full control over their routes so credentials are supplied via + # a basic HTTP authentication prompt. + # There is neither a way to input a mfa credential there nor can we pass + # the user_api_key from localStorage so mfa should be disabled for these routes. + if request.full_path.startswith("/munin"): + return (True, []) + # Try the enabled MFA modes. hints = set() for mfa_mode in mfa_state: diff --git a/management/status_checks.py b/management/status_checks.py index d3fb7ae5..e0869f76 100755 --- a/management/status_checks.py +++ b/management/status_checks.py @@ -857,7 +857,7 @@ def get_latest_miab_version(): from socket import timeout try: - return re.search(b'TAG=(.*)', urlopen("https://raw.githubusercontent.com/ddavness/power-mailinabox/master/setup/bootstrap.sh", timeout=5).read()).group(1).decode("utf8") + return re.search(b'TAG=(.*)', urlopen("https://mailinabox.email/setup.sh?ping=1", timeout=5).read()).group(1).decode("utf8") except (HTTPError, URLError, timeout): return None @@ -870,16 +870,16 @@ def check_miab_version(env, output): this_ver = "Unknown" if config.get("privacy", True): - output.print_warning("You are running version Mail-in-a-Box %s. Mail-in-a-Box version check disabled by privacy setting." % this_ver) + output.print_warning("You are running version Mail-in-a-Box %s Kiekerjan Edition. Mail-in-a-Box version check disabled by privacy setting." % this_ver) else: latest_ver = get_latest_miab_version() if this_ver == latest_ver: - output.print_ok("Mail-in-a-Box is up to date. You are running version %s." % this_ver) + output.print_ok("Mail-in-a-Box is up to date. You are running version %s Kiekerjan Edition." % this_ver) elif latest_ver is None: - output.print_error("Latest Mail-in-a-Box version could not be determined. You are running version %s." % this_ver) + output.print_error("Latest Mail-in-a-Box version could not be determined. You are running version %s Kiekerjan Edition." % this_ver) else: - output.print_error("A new version of Mail-in-a-Box is available. You are running version %s. The latest version is %s. For upgrade instructions, see https://mailinabox.email. " + output.print_error("A new version of Mail-in-a-Box is available. You are running version %s Kiekerjan Edition. The latest version is %s. For upgrade instructions, see https://mailinabox.email. " % (this_ver, latest_ver)) def run_and_output_changes(env, pool): diff --git a/management/web_update.py b/management/web_update.py index 36e9e9e1..c112ba04 100644 --- a/management/web_update.py +++ b/management/web_update.py @@ -8,6 +8,7 @@ from mailconfig import get_mail_domains from dns_update import get_custom_dns_config, get_dns_zones from ssl_certificates import get_ssl_certificates, get_domain_ssl_files, check_certificate from utils import shell, safe_domain_name, sort_domains, get_php_version +from wwwconfig import get_www_domains def get_web_domains(env, include_www_redirects=True, exclude_dns_elsewhere=True): # What domains should we serve HTTP(S) for? @@ -18,11 +19,15 @@ def get_web_domains(env, include_www_redirects=True, exclude_dns_elsewhere=True) # if the user wants to make one. domains |= get_mail_domains(env) + # Add domains for which we only serve www + domains |= get_www_domains(domains) + if include_www_redirects: # Add 'www.' subdomains that we want to provide default redirects # to the main domain for. We'll add 'www.' to any DNS zones, i.e. # the topmost of each domain we serve. domains |= set('www.' + zone for zone, zonefile in get_dns_zones(env)) + domains |= set('www.' + wwwdomain for wwwdomain in get_www_domains(get_mail_domains(env))) # Add Autoconfiguration domains for domains that there are user accounts at: # 'autoconfig.' for Mozilla Thunderbird auto setup. @@ -83,6 +88,7 @@ def do_web_update(env): template1 = open(os.path.join(os.path.dirname(__file__), "../conf/nginx-alldomains.conf")).read() template2 = open(os.path.join(os.path.dirname(__file__), "../conf/nginx-primaryonly.conf")).read() template3 = "\trewrite ^(.*) https://$REDIRECT_DOMAIN$1 permanent;\n" + template4 = open(os.path.join(os.path.dirname(__file__), "../conf/nginx-webonlydomains.conf")).read() # Add the PRIMARY_HOST configuration first so it becomes nginx's default server. nginx_conf += make_domain_config(env['PRIMARY_HOSTNAME'], [template0, template1, template2], ssl_certificates, env) @@ -90,6 +96,8 @@ def do_web_update(env): # Add configuration all other web domains. has_root_proxy_or_redirect = get_web_domains_with_root_overrides(env) web_domains_not_redirect = get_web_domains(env, include_www_redirects=False) + web_only_domains = get_www_domains(get_mail_domains(env)) + for domain in get_web_domains(env): if domain == env['PRIMARY_HOSTNAME']: # PRIMARY_HOSTNAME is handled above. @@ -97,6 +105,9 @@ def do_web_update(env): if domain in web_domains_not_redirect: # This is a regular domain. if domain not in has_root_proxy_or_redirect: + if domain in web_only_domains: + nginx_conf += make_domain_config(domain, [template0, template4], ssl_certificates, env) + else: nginx_conf += make_domain_config(domain, [template0, template1], ssl_certificates, env) else: nginx_conf += make_domain_config(domain, [template0], ssl_certificates, env) diff --git a/management/wwwconfig.py b/management/wwwconfig.py new file mode 100644 index 00000000..794a4c0e --- /dev/null +++ b/management/wwwconfig.py @@ -0,0 +1,34 @@ +import os.path, idna, sys, collections + +def get_www_domains(domains_to_skip): + # Returns the domain names (IDNA-encoded) of all of the domains that are configured to serve www + # on the system. + domains = [] + + try: + # read a line from text file + with open("/etc/miabwwwdomains.conf") as file_in: + for line in file_in: + # Valid domain check future extention: use validators module + # Only one dot allowed + if line.count('.') == 1: + www_domain = get_domain(line, as_unicode=False) + if www_domain not in domains_to_skip: + domains.append(www_domain) + except: + # ignore failures + pass + + return set(domains) + + +def get_domain(domaintxt, as_unicode=True): + ret = domaintxt.rstrip() + if as_unicode: + try: + ret = idna.decode(ret.encode('ascii')) + except (ValueError, UnicodeError, idna.IDNAError): + pass + + return ret + diff --git a/setup/additionals.sh b/setup/additionals.sh new file mode 100644 index 00000000..c0812173 --- /dev/null +++ b/setup/additionals.sh @@ -0,0 +1,20 @@ +source /etc/mailinabox.conf +source setup/functions.sh + +# Cleanup old spam and trash email +cp -f conf/cron/local_clean_mail /etc/cron.weekly/ +chmod +x /etc/cron.weekly/local_clean_mail + +# Reduce logs by not logging mail output in syslog +sed -i "s/\*\.\*;auth,authpriv.none.*\-\/var\/log\/syslog/\*\.\*;mail,auth,authpriv.none \-\/var\/log\/syslog/g" /etc/rsyslog.d/50-default.conf + +# Reduce logs by only logging ufw in ufw.log +sed -i "s/#\& stop/\& stop/g" /etc/rsyslog.d/20-ufw.conf + +restart_service rsyslog + +# decrease time journal is stored +tools/editconf.py /etc/systemd/journald.conf MaxRetentionSec=2month +tools/editconf.py /etc/systemd/journald.conf MaxFileSec=1week + +hide_output systemctl restart systemd-journald.service diff --git a/setup/bootstrap.sh b/setup/bootstrap.sh index f61c9922..a20181ff 100644 --- a/setup/bootstrap.sh +++ b/setup/bootstrap.sh @@ -35,7 +35,7 @@ if [ ! -d $HOME/mailinabox ]; then echo Downloading Mail-in-a-Box $TAG. . . git clone \ -b $TAG --depth 1 \ - https://github.com/ddavness/power-mailinabox \ + https://github.com/mail-in-a-box/mailinabox \ $HOME/mailinabox \ < /dev/null 2> /dev/null diff --git a/setup/munin.sh b/setup/munin.sh index 6799cad6..5b95fde2 100755 --- a/setup/munin.sh +++ b/setup/munin.sh @@ -23,14 +23,15 @@ includedir /etc/munin/munin-conf.d # path dynazoom uses for requests cgiurl_graph /admin/munin/cgi-graph +# send alerts to the following address +contact.admin.command mail -s "Munin notification \${var:host}" administrator@$PRIMARY_HOSTNAME +contact.admin.always_send warning critical + # a simple host tree [$PRIMARY_HOSTNAME] address 127.0.0.1 -# send alerts to the following address contacts admin -contact.admin.command mail -s "Munin notification \${var:host}" administrator@$PRIMARY_HOSTNAME -contact.admin.always_send warning critical EOF # The Debian installer touches these files and chowns them to www-data:adm for use with spawn-fcgi @@ -70,6 +71,11 @@ hide_output systemctl daemon-reload hide_output systemctl unmask munin.service hide_output systemctl enable munin.service +# Some more munin plugins +ln -fs /usr/share/munin/plugins/postfix_mailstats /etc/munin/plugins/ +ln -fs /usr/share/munin/plugins/spamstats /etc/munin/plugins +ln -fs /usr/share/munin/plugins/df_abs /etc/munin/plugins + # Restart services. restart_service munin restart_service munin-node diff --git a/setup/nextcloud.sh b/setup/nextcloud.sh index ae4668bb..1617d33c 100755 --- a/setup/nextcloud.sh +++ b/setup/nextcloud.sh @@ -42,6 +42,9 @@ InstallNextcloud() { mv /usr/local/lib/nextcloud /usr/local/lib/owncloud rm -f /tmp/nextcloud.zip + # Empty the skeleton dir to save some space for each new user + rm -f /usr/local/lib/owncloud/core/skeleton/* + # The two apps we actually want are not in Nextcloud core. Download the releases from # their github repositories. mkdir -p /usr/local/lib/owncloud/apps diff --git a/setup/questions.sh b/setup/questions.sh index 5e3da75e..3beeb2ac 100644 --- a/setup/questions.sh +++ b/setup/questions.sh @@ -119,6 +119,23 @@ if [ -z "${PUBLIC_IP:-}" ]; then fi fi + +if [ -z "${ADMIN_HOME_IP:-}" ]; then + if [ -z "${DEFAULT_ADMIN_HOME_IP:-}" ]; then + input_box "Admin Home IP Address" \ + "Enter the public IP address of the admin home, as given to you by your ISP. + \n\nAdmin Home IP address:" \ + "" \ + ADMIN_HOME_IP + else + ADMIN_HOME_IP=$DEFAULT_ADMIN_HOME_IP + fi +fi + +if [ -z "${ADMIN_HOME_IP:-}" ]; then + ADMIN_HOME_IP="" +fi + # Same for IPv6. But it's optional. Also, if it looks like the system # doesn't have an IPv6, don't ask for one. if [ -z "${PUBLIC_IPV6:-}" ]; then @@ -206,6 +223,9 @@ fi if [ "$PRIVATE_IPV6" != "$PUBLIC_IPV6" ]; then echo "Private IPv6 Address: $PRIVATE_IPV6" fi +if [ -n "$ADMIN_HOME_IP" ]; then + echo "Admin Home IP Address: $ADMIN_HOME_IP" +fi if [ -f /usr/bin/git ] && [ -d .git ]; then echo "Mail-in-a-Box Version: " $(git describe --tags) fi diff --git a/setup/spamassassin.sh b/setup/spamassassin.sh index 989bbff4..6d5195e1 100755 --- a/setup/spamassassin.sh +++ b/setup/spamassassin.sh @@ -195,3 +195,4 @@ chmod 770 $STORAGE_ROOT/mail/spamassassin restart_service spampd restart_service dovecot +systemctl enable spamassassin.service \ No newline at end of file diff --git a/setup/start.sh b/setup/start.sh index 404e0410..06349e3e 100755 --- a/setup/start.sh +++ b/setup/start.sh @@ -100,6 +100,7 @@ PUBLIC_IPV6=$PUBLIC_IPV6 PRIVATE_IP=$PRIVATE_IP PRIVATE_IPV6=$PRIVATE_IPV6 MTA_STS_MODE=${MTA_STS_MODE-} +ADMIN_HOME_IP=$ADMIN_HOME_IP EOF # Start service configuration. @@ -114,9 +115,10 @@ source setup/spamassassin.sh source setup/web.sh source setup/webmail.sh source setup/nextcloud.sh -source setup/zpush.sh +#source setup/zpush.sh source setup/management.sh source setup/munin.sh +source setup/additionals.sh # Wait for the management daemon to start... until nc -z -w 4 127.0.0.1 10222 diff --git a/setup/system.sh b/setup/system.sh index c19f36d1..e09a1846 100755 --- a/setup/system.sh +++ b/setup/system.sh @@ -339,9 +339,14 @@ rm -f /etc/fail2ban/jail.local # we used to use this file but don't anymore rm -f /etc/fail2ban/jail.d/defaults-debian.conf # removes default config so we can manage all of fail2ban rules in one config cat conf/fail2ban/jails.conf \ | sed "s/PUBLIC_IP/$PUBLIC_IP/g" \ + | sed "s/ADMIN_HOME_IP/$ADMIN_HOME_IP/g" \ | sed "s#STORAGE_ROOT#$STORAGE_ROOT#" \ - > /etc/fail2ban/jail.d/mailinabox.conf + > /etc/fail2ban/jail.d/00-mailinabox.conf cp -f conf/fail2ban/filter.d/* /etc/fail2ban/filter.d/ +cp -f conf/fail2ban/jail.d/* /etc/fail2ban/jail.d/ + +# fail2ban should be able to look back far enough because we increased findtime of recidive jail +tools/editconf.py /etc/fail2ban/fail2ban.conf dbpurgeage=7d # On first installation, the log files that the jails look at don't all exist. # e.g., The roundcube error log isn't normally created until someone logs into diff --git a/setup/webmail.sh b/setup/webmail.sh index bdc08ba3..a043f678 100755 --- a/setup/webmail.sh +++ b/setup/webmail.sh @@ -32,8 +32,8 @@ VERSION=1.4.10 HASH=36b2351030e1ebddb8e39190d7b0ba82b1bbec1b PERSISTENT_LOGIN_VERSION=6b3fc450cae23ccb2f393d0ef67aa319e877e435 HTML5_NOTIFIER_VERSION=4b370e3cd60dabd2f428a26f45b677ad1b7118d5 -CARDDAV_VERSION=3.0.3 -CARDDAV_HASH=d1e3b0d851ffa2c6bd42bf0c04f70d0e1d0d78f8 +CARDDAV_VERSION=4.1.1 +CARDDAV_HASH=87b73661b7799b2079c28324311eddb4241242bb UPDATE_KEY=$VERSION:$PERSISTENT_LOGIN_VERSION:$HTML5_NOTIFIER_VERSION:$CARDDAV_VERSION @@ -76,7 +76,7 @@ if [ $needs_update == 1 ]; then # download and verify the full release of the carddav plugin wget_verify \ - https://github.com/blind-coder/rcmcarddav/releases/download/v${CARDDAV_VERSION}/carddav-${CARDDAV_VERSION}.zip \ + https://github.com/mstilkerich/rcmcarddav/releases/download/v${CARDDAV_VERSION}/carddav-${CARDDAV_VERSION}.zip \ $CARDDAV_HASH \ /tmp/carddav.zip @@ -144,7 +144,7 @@ cat > ${RCM_PLUGIN_DIR}/carddav/config.inc.php < 'ownCloud', 'username' => '%u', // login username 'password' => '%p', // login password - 'url' => 'https://${PRIMARY_HOSTNAME}/cloud/remote.php/carddav/addressbooks/%u/contacts', + 'url' => 'https://${PRIMARY_HOSTNAME}/cloud/remote.php/dav/addressbooks/users/%u/contacts', 'active' => true, 'readonly' => false, 'refresh_time' => '02:00:00', diff --git a/tools/goiplookup.gz b/tools/goiplookup.gz new file mode 100644 index 00000000..f8c41569 Binary files /dev/null and b/tools/goiplookup.gz differ