#!/usr/bin/env bash tmp_err_msg=$(mktemp) # ------------- # --- Some functions # ------------- clean_up() { # Perform program exit housekeeping rm -f $tmp_err_msg exit $1 } echononl(){ echo X\\c > /tmp/shprompt$$ if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then echo -e -n "$*\\c" 1>&2 else echo -e -n "$*" 1>&2 fi rm /tmp/shprompt$$ } fatal(){ echo "" echo -e "fatal error: $*" echo "" echo -e "\t\033[31m\033[1mInstalllation will be interrupted\033[m\033[m" echo "" exit 1 } error(){ echo "" echo -e "\t[ \033[31m\033[1mFehler\033[m ]: $*" echo "" } warn (){ echo "" echo -e "\t[ \033[33m\033[1mWarning\033[m ]: $*" echo "" } info (){ echo "" echo -e "\t[ \033[32m\033[1mInfo\033[m ]: $*" echo "" } echo_done() { echo -e "\033[80G[ \033[32mdone\033[m ]" } echo_ok() { echo -e "\033[80G[ \033[32mok\033[m ]" } echo_warning() { echo -e "\033[80G[ \033[33m\033[1mwarn\033[m ]" } echo_failed(){ echo -e "\033[80G[ \033[1;31mfailed\033[m ]" } echo_skipped() { echo -e "\033[80G[ \033[33m\033[1mskipped\033[m ]" } ## - Install Postfix Firewall Daemon from debian packages system ## - echononl " Install Postfix Firewall Daemon from debian packages system" _pkg="postfwd" if aptitude search $_pkg | grep " $_pkg " | grep -e "^i" > /dev/null 2>&1 ; then echo_skipped else DEBIAN_FRONTEND=noninteractive apt-get -y install $_pkg > /dev/null 2> $tmp_err_msg if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $tmp_err_msg)" fi fi echononl " Adjust /etc/default/postfwd" perl -i -n -p -e "s#^(\s*)(STARTUP=.*)#\#\1\2\nSTARTUP=1#" \ /etc/default/postfwd > $tmp_err_msg 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $tmp_err_msg)" fi _file="/etc/postfix/postfwd.wl-nets" echononl " Create whitelist file '$_file' for postfwd" if [[ ! -f "$_file" ]]; then cat << EOF > "$_file" # --- # Trusted networks whitelisted by postfwd # # Example: # # # web0.warenform.de # #83.223.86.76 # #2a01:30:0:505:286:96ff:fe4a:6ee # #2a01:30:0:13:286:96ff:fe4a:6eee # # --- # give truested networrk adresses here EOF if [[ $? -eq 0 ]] ; then echo_ok else echo_failed fi else echo_skipped fi _file="/etc/postfix/postfwd.wl-hosts" echononl " Create whitelist file '$_file' for postfwd" if [[ ! -f "$_file" ]]; then cat << EOF > "$_file" # --- # Trusted hosts whitelisted by postfwd # # This file is called with '=~'. This means perl regexp is possible # # Example: # # # all hosts of domain 'oopen.de' # \.oopen\.de$ # # # host a.mx.oopen.de # a.mx.oopen.de # # --- # give truested hostnames here EOF if [[ $? -eq 0 ]] ; then echo_ok else echo_failed fi else echo_skipped fi _file="/etc/postfix/postfwd.wl-user" echononl " Create whitelist file '$_file' for postfwd" if [[ ! -f "$_file" ]]; then cat << EOF > "$_file" # --- # SASL Users whitelisted by postfwd # # Example: # # # give trusted sasl_user here # admin@warenform.de # # --- # give trusted sasl_user here EOF if [[ $? -eq 0 ]] ; then echo_ok else echo_failed fi else echo_skipped fi _file="/etc/postfix/postfwd.wl-sender" echononl " Create whitelist file '$_file' for postfwd" if [[ ! -f "$_file" ]]; then cat << EOF > "$_file" # --- # Trusted senders whitelisted by postfwd # # This file is called with '=~'. This means perl regexp is possible # # Example: # # # all senders of maildomaindomain 'oopen.de' # @oopen\.de$ # # # sender address ckubu@oopen.de # ckubu@oopen.de # # --- # give trusted sender addresses here EOF if [[ $? -eq 0 ]] ; then echo_ok else echo_failed fi else echo_skipped fi _file="/etc/postfix/postfwd.bl-nets" echononl " Create whitelist file '$_file' for postfwd" if [[ ! -f "$_file" ]]; then cat << EOF > "$_file" # --- # Networks blocked by postfwd # # Example: # # # web0.warenform.de # #83.223.86.76 # #2a01:30:0:505:286:96ff:fe4a:6ee # #2a01:30:0:13:286:96ff:fe4a:6eee # # --- # give networks to block here EOF if [[ $? -eq 0 ]] ; then echo_ok else echo_failed fi else echo_skipped fi _file="/etc/postfix/postfwd.bl-hosts" echononl " Create whitelist file '$_file' for postfwd" if [[ ! -f "$_file" ]]; then cat << EOF > "$_file" # --- # hosts blocked by postfwd # # This file is called with '=~'. This means perl regexp is possible # # Example: # # # block all hosts of domain 'oopen.de' # \.oopen\.de$ # # # block host a.mx.oopen.de # a.mx.oopen.de # # --- # give hostnames to blocke here EOF if [[ $? -eq 0 ]] ; then echo_ok else echo_failed fi else echo_skipped fi _file="/etc/postfix/postfwd.bl-user" echononl " Create whitelist file '$_file' for postfwd" if [[ ! -f "$_file" ]]; then cat << EOF > "$_file" # --- # SASL Users blocked by postfwd # # Example: # # # give sasl_user to block here # ckubu@warenform.de # --- # give sasl_user to block here EOF if [[ $? -eq 0 ]] ; then echo_ok else echo_failed fi else echo_skipped fi _file="/etc/postfix/postfwd.bl-sender" echononl " Create whitelist file '$_file' for postfwd" if [[ ! -f "$_file" ]]; then cat << EOF > "$_file" # --- # Sender addresses blocked by postfwd # # This file is called with '=~'. This means perl regexp is possible # # Example: # # # all senders of maildomaindomain 'oopen.de' # @oopen\.de$ # # # sender address ckubu@oopen.de # ckubu@oopen.de # # --- # annoying spammer domains @acieu.co.uk # annoying spammer addresses error@mailfrom.com EOF if [[ $? -eq 0 ]] ; then echo_ok else echo_failed fi else echo_skipped fi echononl " Create configuration file '/etc/postfix/postfwd.cf'.." #if [[ ! -f "/etc/postfix/postfwd.cf" ]]; then cat << EOF > /etc/postfix/postfwd.cf #======= Definitions ============ # Match messages with an associated SASL username &&SASL_AUTH { sasl_username!~^\$ } # Trusted networks &&TRUSTED_NETS { client_address==file:/etc/postfix/postfwd.wl-nets } # Trusted hostnames # client_name~=.warenform.de$ &&TRUSTED_HOSTS { client_name=~file:/etc/postfix/postfwd.wl-hosts } # Trusted users &&TRUSTED_USERS { sasl_username==file:/etc/postfix/postfwd.wl-user } # Trusted senders &&TRUSTED_SENDERS { sender=~file:/etc/postfix/postfwd.wl-sender } # Blacklist networks &&BLOCK_NETS { client_address==file:/etc/postfix/postfwd.bl-nets } # Blacklist hostnames &&BLOCK_HOSTS { client_name=~file:/etc/postfix/postfwd.bl-hosts } # Blacklist users &&BLOCK_USERS { sasl_username==file:/etc/postfix/postfwd.bl-user } # Blacklist sender adresses &&BLOCK_SENDER { # =~ # using '=~' allows also matching entries for domains (i.e. @acieu.co.uk) sender=~file:/etc/postfix/postfwd.bl-sender } # Inbound emails only &&INCOMING { client_address!=127.0.0.1 } #======= Rule Sets ============ # --- # # Processing of the Rule Sets # # The parser checks the elements of a policy delegation request against the postfwd set # of rules and, if necessary, triggers the configured action (action=). Similar to a # classic firewall, a rule is considered true if every element of the set of rules (or # one from every element list) applies to the comparison. I.e. the following rule: # # client_address=1.1.1.1, 1.1.1.2; client_name==unknown; action=REJECT # # triggers a REJECT if the # # Client address is equal (1.1.1.1 OR 1.1.1.2) AND the client name 'unknown' # # # Note: # If an element occurs more than once, an element list is formed: # # The following rule set is equivalent to the above: # # client_address=1.1.1.1; client_address=1.1.1.2; client_name==unknown; action=REJECT # # # triggers a REJECT if (as above) the # # Client address (1.1.1.1 OR 1.1.1.2) AND the client name 'unknown' # # --- # Whitelists # Whitelist trusted networks id=WHL_NETS &&TRUSTED_NETS action=DUNNO # Whitelist trusted hostnames id=WHL_HOSTS &&TRUSTED_HOSTS action=DUNNO # Whitelist sasl users id=WHL_USERS &&TRUSTED_USERS action=DUNNO # Whitelist senders id=WHL_SENDERS &&INCOMING &&TRUSTED_SENDERS action=DUNNO # Blacklists # Block networks id=BL_NETS &&BLOCK_NETS action=REJECT Network Address \$\$client_address blocked by Mailserver admins. Error: BL_NETS # Block hostname id=BL_HOSTS &&BLOCK_HOSTS action=REJECT \$\$client_name blocked by Mailserver admins. Error: BL_HOSTS # Block users id=BL_USERS &&BLOCK_USERS action=REJECT User is blocked by Mailserver admins. Error: BL_USERS # Blacklist sender # # Claim successful delivery and silently discard the message. # id=BL_SENDER &&BLOCK_SENDER #action=DISCARD action=REJECT Sender address is blocked by Mailserver admins. Error: BL_SENDER # Rate Limits # Throttle unknown clients to 5 recipients per 5 minutes: id=RATE_UNKNOWN_CLIENT_ADDR sasl_username =~ /^$/ client_name==unknown action=rate(client_address/5/300/450 4.7.1 only 5 recipients per 5 minutes allowed) # Block clients (ip-addresses) sending more than 50 messages per minute exceeded. Error:RATE_CLIENT) id=RATE_CLIENT_ADDR &&INCOMING action=rate(\$\$client_address/50/60/421 421 4.7.0 Too many connections from \$\$client_address) # Block messages with more than 50 recipients id=BLOCK_MSG_RCPT &&INCOMING &&SASL_AUTH recipient_count=50 action=REJECT Too many recipients, please reduce to less than 50 or consider using a mailing list. Error: BLOCK_MSG_RCPT # Block users sending more than 50 messages/hour id=RATE_MSG &&INCOMING &&SASL_AUTH action=rate(\$\$sasl_username/50/3600/450 4.7.1 Number messages per hour exceeded. Error:RATE_MSG) # Block users sending more than 250 recipients total/hour id=RATE_RCPT &&INCOMING &&SASL_AUTH action=rcpt(\$\$sasl_username/250/3600/450 4.7.1 Number recipients per hour exceeded. Error:RATE_RCPT) EOF if [[ $? -eq 0 ]] ; then echo_ok else echo_failed fi #else # echo_skipped #fi echononl " Restart Postfix firewall daemon 'postfwd'.." if $systemd_exists ; then systemctl restart postfwd > /dev/null 2> $tmp_err_msg if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $tmp_err_msg)" fi else /etc/init.d/postfwd restart > /dev/null 2> $tmp_err_msg if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $tmp_err_msg)" fi fi warn "Postfix firewall daemin is installed, but not integrated in postfix mailsystem (/etc/postfix/main.cf)" clean_up 0