538 lines
10 KiB
Bash
Executable File
538 lines
10 KiB
Bash
Executable File
#!/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
|