parent
055183257d
commit
1e59816665
|
@ -1,11 +1,11 @@
|
||||||
FROM alpine:3.6
|
FROM alpine:3.8
|
||||||
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
ENV XTABLES_LIBDIR /usr/lib/xtables
|
ENV XTABLES_LIBDIR /usr/lib/xtables
|
||||||
ENV PYTHON_IPTABLES_XTABLES_VERSION 12
|
ENV PYTHON_IPTABLES_XTABLES_VERSION 12
|
||||||
ENV IPTABLES_LIBDIR /usr/lib
|
ENV IPTABLES_LIBDIR /usr/lib
|
||||||
|
|
||||||
RUN apk add -U python2 python-dev py-pip gcc musl-dev iptables ip6tables \
|
RUN apk add -U python2 python-dev py-pip gcc musl-dev iptables ip6tables tzdata \
|
||||||
&& pip2 install --upgrade python-iptables==0.13.0 redis ipaddress \
|
&& pip2 install --upgrade python-iptables==0.13.0 redis ipaddress \
|
||||||
&& apk del python-dev py2-pip gcc
|
&& apk del python-dev py2-pip gcc
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,9 @@ import time
|
||||||
import atexit
|
import atexit
|
||||||
import signal
|
import signal
|
||||||
import ipaddress
|
import ipaddress
|
||||||
import subprocess
|
from random import randint
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
from threading import Lock
|
||||||
import redis
|
import redis
|
||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
|
@ -27,6 +28,7 @@ RULES[6] = 'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
|
||||||
bans = {}
|
bans = {}
|
||||||
log = {}
|
log = {}
|
||||||
quit_now = False
|
quit_now = False
|
||||||
|
lock = Lock()
|
||||||
|
|
||||||
def refreshF2boptions():
|
def refreshF2boptions():
|
||||||
global f2boptions
|
global f2boptions
|
||||||
|
@ -55,38 +57,41 @@ def refreshF2boptions():
|
||||||
if r.exists('F2B_LOG'):
|
if r.exists('F2B_LOG'):
|
||||||
r.rename('F2B_LOG', 'NETFILTER_LOG')
|
r.rename('F2B_LOG', 'NETFILTER_LOG')
|
||||||
|
|
||||||
def checkChainOrder():
|
def mailcowChainOrder():
|
||||||
|
global lock
|
||||||
global quit_now
|
global quit_now
|
||||||
while not quit_now:
|
while not quit_now:
|
||||||
time.sleep(20)
|
time.sleep(10)
|
||||||
filter4_table = iptc.Table(iptc.Table.FILTER)
|
with lock:
|
||||||
filter6_table = iptc.Table6(iptc.Table6.FILTER)
|
filter4_table = iptc.Table(iptc.Table.FILTER)
|
||||||
filter4_table.refresh()
|
filter6_table = iptc.Table6(iptc.Table6.FILTER)
|
||||||
filter6_table.refresh()
|
filter4_table.refresh()
|
||||||
for f in [filter4_table, filter6_table]:
|
filter6_table.refresh()
|
||||||
forward_chain = iptc.Chain(f, 'FORWARD')
|
for f in [filter4_table, filter6_table]:
|
||||||
input_chain = iptc.Chain(f, 'INPUT')
|
forward_chain = iptc.Chain(f, 'FORWARD')
|
||||||
for chain in [forward_chain, input_chain]:
|
input_chain = iptc.Chain(f, 'INPUT')
|
||||||
target_found = False
|
for chain in [forward_chain, input_chain]:
|
||||||
for position, item in enumerate(chain.rules):
|
target_found = False
|
||||||
if item.target.name == 'MAILCOW':
|
for position, item in enumerate(chain.rules):
|
||||||
target_found = True
|
if item.target.name == 'MAILCOW':
|
||||||
if position != 0:
|
target_found = True
|
||||||
log['time'] = int(round(time.time()))
|
if position != 0:
|
||||||
log['priority'] = 'crit'
|
log['time'] = int(round(time.time()))
|
||||||
log['message'] = 'Error in ' + chain.name + ' chain order, restarting container'
|
log['priority'] = 'crit'
|
||||||
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
log['message'] = 'Error in ' + chain.name + ' chain order, restarting container'
|
||||||
print log['message']
|
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
quit_now = True
|
print log['message']
|
||||||
if not target_found:
|
quit_now = True
|
||||||
log['time'] = int(round(time.time()))
|
if not target_found:
|
||||||
log['priority'] = 'crit'
|
log['time'] = int(round(time.time()))
|
||||||
log['message'] = 'Error in ' + chain.name + ' chain: target not found, restarting container'
|
log['priority'] = 'crit'
|
||||||
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
log['message'] = 'Error in ' + chain.name + ' chain: MAILCOW target not found, restarting container'
|
||||||
print log['message']
|
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
quit_now = True
|
print log['message']
|
||||||
|
quit_now = True
|
||||||
|
|
||||||
def ban(address):
|
def ban(address):
|
||||||
|
global lock
|
||||||
refreshF2boptions()
|
refreshF2boptions()
|
||||||
BAN_TIME = int(f2boptions['ban_time'])
|
BAN_TIME = int(f2boptions['ban_time'])
|
||||||
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
|
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
|
||||||
|
@ -135,21 +140,23 @@ def ban(address):
|
||||||
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
print 'Banning %s for %d minutes' % (net, BAN_TIME / 60)
|
print 'Banning %s for %d minutes' % (net, BAN_TIME / 60)
|
||||||
if type(ip) is ipaddress.IPv4Address:
|
if type(ip) is ipaddress.IPv4Address:
|
||||||
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW')
|
with lock:
|
||||||
rule = iptc.Rule()
|
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW')
|
||||||
rule.src = net
|
rule = iptc.Rule()
|
||||||
target = iptc.Target(rule, "REJECT")
|
rule.src = net
|
||||||
rule.target = target
|
target = iptc.Target(rule, "REJECT")
|
||||||
if rule not in chain.rules:
|
rule.target = target
|
||||||
chain.insert_rule(rule)
|
if rule not in chain.rules:
|
||||||
|
chain.insert_rule(rule)
|
||||||
else:
|
else:
|
||||||
chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW')
|
with lock:
|
||||||
rule = iptc.Rule6()
|
chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW')
|
||||||
rule.src = net
|
rule = iptc.Rule6()
|
||||||
target = iptc.Target(rule, "REJECT")
|
rule.src = net
|
||||||
rule.target = target
|
target = iptc.Target(rule, "REJECT")
|
||||||
if rule not in chain.rules:
|
rule.target = target
|
||||||
chain.insert_rule(rule)
|
if rule not in chain.rules:
|
||||||
|
chain.insert_rule(rule)
|
||||||
r.hset('F2B_ACTIVE_BANS', '%s' % net, log['time'] + BAN_TIME)
|
r.hset('F2B_ACTIVE_BANS', '%s' % net, log['time'] + BAN_TIME)
|
||||||
else:
|
else:
|
||||||
log['time'] = int(round(time.time()))
|
log['time'] = int(round(time.time()))
|
||||||
|
@ -159,6 +166,7 @@ def ban(address):
|
||||||
print '%d more attempts in the next %d seconds until %s is banned' % (MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net)
|
print '%d more attempts in the next %d seconds until %s is banned' % (MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net)
|
||||||
|
|
||||||
def unban(net):
|
def unban(net):
|
||||||
|
global lock
|
||||||
log['time'] = int(round(time.time()))
|
log['time'] = int(round(time.time()))
|
||||||
log['priority'] = 'info'
|
log['priority'] = 'info'
|
||||||
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
|
@ -172,21 +180,23 @@ def unban(net):
|
||||||
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
print 'Unbanning %s' % net
|
print 'Unbanning %s' % net
|
||||||
if type(ipaddress.ip_network(net.decode('ascii'))) is ipaddress.IPv4Network:
|
if type(ipaddress.ip_network(net.decode('ascii'))) is ipaddress.IPv4Network:
|
||||||
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW')
|
with lock:
|
||||||
rule = iptc.Rule()
|
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW')
|
||||||
rule.src = net
|
rule = iptc.Rule()
|
||||||
target = iptc.Target(rule, "REJECT")
|
rule.src = net
|
||||||
rule.target = target
|
target = iptc.Target(rule, "REJECT")
|
||||||
if rule in chain.rules:
|
rule.target = target
|
||||||
chain.delete_rule(rule)
|
if rule in chain.rules:
|
||||||
|
chain.delete_rule(rule)
|
||||||
else:
|
else:
|
||||||
chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW')
|
with lock:
|
||||||
rule = iptc.Rule6()
|
chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW')
|
||||||
rule.src = net
|
rule = iptc.Rule6()
|
||||||
target = iptc.Target(rule, "REJECT")
|
rule.src = net
|
||||||
rule.target = target
|
target = iptc.Target(rule, "REJECT")
|
||||||
if rule in chain.rules:
|
rule.target = target
|
||||||
chain.delete_rule(rule)
|
if rule in chain.rules:
|
||||||
|
chain.delete_rule(rule)
|
||||||
r.hdel('F2B_ACTIVE_BANS', '%s' % net)
|
r.hdel('F2B_ACTIVE_BANS', '%s' % net)
|
||||||
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
|
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
|
||||||
if net in bans:
|
if net in bans:
|
||||||
|
@ -197,6 +207,7 @@ def quit(signum, frame):
|
||||||
quit_now = True
|
quit_now = True
|
||||||
|
|
||||||
def clear():
|
def clear():
|
||||||
|
global lock
|
||||||
log['time'] = int(round(time.time()))
|
log['time'] = int(round(time.time()))
|
||||||
log['priority'] = 'info'
|
log['priority'] = 'info'
|
||||||
log['message'] = 'Clearing all bans'
|
log['message'] = 'Clearing all bans'
|
||||||
|
@ -204,29 +215,30 @@ def clear():
|
||||||
print 'Clearing all bans'
|
print 'Clearing all bans'
|
||||||
for net in bans.copy():
|
for net in bans.copy():
|
||||||
unban(net)
|
unban(net)
|
||||||
filter4_table = iptc.Table(iptc.Table.FILTER)
|
with lock:
|
||||||
filter6_table = iptc.Table6(iptc.Table6.FILTER)
|
filter4_table = iptc.Table(iptc.Table.FILTER)
|
||||||
for filter_table in [filter4_table, filter6_table]:
|
filter6_table = iptc.Table6(iptc.Table6.FILTER)
|
||||||
filter_table.autocommit = False
|
for filter_table in [filter4_table, filter6_table]:
|
||||||
forward_chain = iptc.Chain(filter_table, "FORWARD")
|
filter_table.autocommit = False
|
||||||
input_chain = iptc.Chain(filter_table, "INPUT")
|
forward_chain = iptc.Chain(filter_table, "FORWARD")
|
||||||
mailcow_chain = iptc.Chain(filter_table, "MAILCOW")
|
input_chain = iptc.Chain(filter_table, "INPUT")
|
||||||
if mailcow_chain in filter_table.chains:
|
mailcow_chain = iptc.Chain(filter_table, "MAILCOW")
|
||||||
for rule in mailcow_chain.rules:
|
if mailcow_chain in filter_table.chains:
|
||||||
mailcow_chain.delete_rule(rule)
|
for rule in mailcow_chain.rules:
|
||||||
for rule in forward_chain.rules:
|
mailcow_chain.delete_rule(rule)
|
||||||
if rule.target.name == 'MAILCOW':
|
for rule in forward_chain.rules:
|
||||||
forward_chain.delete_rule(rule)
|
if rule.target.name == 'MAILCOW':
|
||||||
for rule in input_chain.rules:
|
forward_chain.delete_rule(rule)
|
||||||
if rule.target.name == 'MAILCOW':
|
for rule in input_chain.rules:
|
||||||
input_chain.delete_rule(rule)
|
if rule.target.name == 'MAILCOW':
|
||||||
filter_table.delete_chain("MAILCOW")
|
input_chain.delete_rule(rule)
|
||||||
filter_table.commit()
|
filter_table.delete_chain("MAILCOW")
|
||||||
filter_table.refresh()
|
filter_table.commit()
|
||||||
filter_table.autocommit = True
|
filter_table.refresh()
|
||||||
r.delete('F2B_ACTIVE_BANS')
|
filter_table.autocommit = True
|
||||||
r.delete('F2B_PERM_BANS')
|
r.delete('F2B_ACTIVE_BANS')
|
||||||
pubsub.unsubscribe()
|
r.delete('F2B_PERM_BANS')
|
||||||
|
pubsub.unsubscribe()
|
||||||
|
|
||||||
def watch():
|
def watch():
|
||||||
log['time'] = int(round(time.time()))
|
log['time'] = int(round(time.time()))
|
||||||
|
@ -235,6 +247,7 @@ def watch():
|
||||||
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
pubsub.subscribe('F2B_CHANNEL')
|
pubsub.subscribe('F2B_CHANNEL')
|
||||||
print 'Subscribing to Redis channel F2B_CHANNEL'
|
print 'Subscribing to Redis channel F2B_CHANNEL'
|
||||||
|
|
||||||
while not quit_now:
|
while not quit_now:
|
||||||
for item in pubsub.listen():
|
for item in pubsub.listen():
|
||||||
for rule_id, rule_regex in RULES.iteritems():
|
for rule_id, rule_regex in RULES.iteritems():
|
||||||
|
@ -252,34 +265,81 @@ def watch():
|
||||||
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
ban(addr)
|
ban(addr)
|
||||||
|
|
||||||
def snat(snat_target):
|
def snat4(snat_target):
|
||||||
def get_snat_rule():
|
global lock
|
||||||
|
global quit_now
|
||||||
|
|
||||||
|
def get_snat4_rule():
|
||||||
rule = iptc.Rule()
|
rule = iptc.Rule()
|
||||||
rule.src = os.getenv('IPV4_NETWORK', '172.22.1') + '.0/24'
|
rule.src = os.getenv('IPV4_NETWORK', '172.22.1') + '.0/24'
|
||||||
rule.dst = '!' + rule.src
|
rule.dst = '!' + rule.src
|
||||||
target = rule.create_target("SNAT")
|
target = rule.create_target("SNAT")
|
||||||
target.to_source = snat_target
|
target.to_source = snat_target
|
||||||
return rule
|
return rule
|
||||||
|
|
||||||
while not quit_now:
|
while not quit_now:
|
||||||
time.sleep(5)
|
time.sleep(10)
|
||||||
table = iptc.Table('nat')
|
with lock:
|
||||||
table.refresh()
|
try:
|
||||||
table.autocommit = False
|
table = iptc.Table('nat')
|
||||||
chain = iptc.Chain(table, 'POSTROUTING')
|
table.refresh()
|
||||||
if get_snat_rule() not in chain.rules:
|
chain = iptc.Chain(table, 'POSTROUTING')
|
||||||
log['time'] = int(round(time.time()))
|
table.autocommit = False
|
||||||
log['priority'] = 'info'
|
if get_snat4_rule() not in chain.rules:
|
||||||
log['message'] = 'Added POSTROUTING rule for source network ' + get_snat_rule().src + ' to SNAT target ' + snat_target
|
log['time'] = int(round(time.time()))
|
||||||
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
log['priority'] = 'info'
|
||||||
print log['message']
|
log['message'] = 'Added POSTROUTING rule for source network ' + get_snat4_rule().src + ' to SNAT target ' + snat_target
|
||||||
chain.insert_rule(get_snat_rule())
|
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
table.commit()
|
print log['message']
|
||||||
else:
|
chain.insert_rule(get_snat4_rule())
|
||||||
for position, item in enumerate(chain.rules):
|
table.commit()
|
||||||
if item == get_snat_rule():
|
else:
|
||||||
if position != 0:
|
for position, item in enumerate(chain.rules):
|
||||||
chain.delete_rule(get_snat_rule())
|
if item == get_snat4_rule():
|
||||||
table.commit()
|
if position != 0:
|
||||||
|
chain.delete_rule(get_snat4_rule())
|
||||||
|
table.commit()
|
||||||
|
table.autocommit = True
|
||||||
|
except:
|
||||||
|
print 'Error running SNAT4, retrying...'
|
||||||
|
|
||||||
|
def snat6(snat_target):
|
||||||
|
global lock
|
||||||
|
global quit_now
|
||||||
|
|
||||||
|
def get_snat6_rule():
|
||||||
|
rule = iptc.Rule6()
|
||||||
|
rule.src = os.getenv('IPV6_NETWORK', 'fd4d:6169:6c63:6f77::/64')
|
||||||
|
rule.dst = '!' + rule.src
|
||||||
|
target = rule.create_target("SNAT")
|
||||||
|
target.to_source = snat_target
|
||||||
|
return rule
|
||||||
|
|
||||||
|
while not quit_now:
|
||||||
|
time.sleep(10)
|
||||||
|
with lock:
|
||||||
|
try:
|
||||||
|
table = iptc.Table6('nat')
|
||||||
|
table.refresh()
|
||||||
|
chain = iptc.Chain(table, 'POSTROUTING')
|
||||||
|
table.autocommit = False
|
||||||
|
if get_snat6_rule() not in chain.rules:
|
||||||
|
log['time'] = int(round(time.time()))
|
||||||
|
log['priority'] = 'info'
|
||||||
|
log['message'] = 'Added POSTROUTING rule for source network ' + get_snat6_rule().src + ' to SNAT target ' + snat_target
|
||||||
|
r.lpush('NETFILTER_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
|
print log['message']
|
||||||
|
chain.insert_rule(get_snat6_rule())
|
||||||
|
table.commit()
|
||||||
|
else:
|
||||||
|
for position, item in enumerate(chain.rules):
|
||||||
|
if item == get_snat6_rule():
|
||||||
|
if position != 0:
|
||||||
|
chain.delete_rule(get_snat6_rule())
|
||||||
|
table.commit()
|
||||||
|
table.autocommit = True
|
||||||
|
except:
|
||||||
|
print 'Error running SNAT6, retrying...'
|
||||||
|
|
||||||
def autopurge():
|
def autopurge():
|
||||||
while not quit_now:
|
while not quit_now:
|
||||||
|
@ -297,6 +357,7 @@ def autopurge():
|
||||||
unban(net)
|
unban(net)
|
||||||
|
|
||||||
def initChain():
|
def initChain():
|
||||||
|
# Is called before threads start, no locking
|
||||||
print "Initializing mailcow netfilter chain"
|
print "Initializing mailcow netfilter chain"
|
||||||
# IPv4
|
# IPv4
|
||||||
if not iptc.Chain(iptc.Table(iptc.Table.FILTER), "MAILCOW") in iptc.Table(iptc.Table.FILTER).chains:
|
if not iptc.Chain(iptc.Table(iptc.Table.FILTER), "MAILCOW") in iptc.Table(iptc.Table.FILTER).chains:
|
||||||
|
@ -355,7 +416,6 @@ def initChain():
|
||||||
chain.insert_rule(rule)
|
chain.insert_rule(rule)
|
||||||
r.hset('F2B_PERM_BANS', '%s' % bl_key, int(round(time.time())))
|
r.hset('F2B_PERM_BANS', '%s' % bl_key, int(round(time.time())))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
# In case a previous session was killed without cleanup
|
# In case a previous session was killed without cleanup
|
||||||
|
@ -372,19 +432,30 @@ if __name__ == '__main__':
|
||||||
snat_ip = os.getenv('SNAT_TO_SOURCE').decode('ascii')
|
snat_ip = os.getenv('SNAT_TO_SOURCE').decode('ascii')
|
||||||
snat_ipo = ipaddress.ip_address(snat_ip)
|
snat_ipo = ipaddress.ip_address(snat_ip)
|
||||||
if type(snat_ipo) is ipaddress.IPv4Address:
|
if type(snat_ipo) is ipaddress.IPv4Address:
|
||||||
snat_thread = Thread(target=snat,args=(snat_ip,))
|
snat4_thread = Thread(target=snat4,args=(snat_ip,))
|
||||||
snat_thread.daemon = True
|
snat4_thread.daemon = True
|
||||||
snat_thread.start()
|
snat4_thread.start()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print os.getenv('SNAT_TO_SOURCE') + ' is not a valid IPv4 address'
|
print os.getenv('SNAT_TO_SOURCE') + ' is not a valid IPv4 address'
|
||||||
|
|
||||||
|
if os.getenv('SNAT6_TO_SOURCE') and os.getenv('SNAT6_TO_SOURCE') is not 'n':
|
||||||
|
try:
|
||||||
|
snat_ip = os.getenv('SNAT6_TO_SOURCE').decode('ascii')
|
||||||
|
snat_ipo = ipaddress.ip_address(snat_ip)
|
||||||
|
if type(snat_ipo) is ipaddress.IPv6Address:
|
||||||
|
snat6_thread = Thread(target=snat6,args=(snat_ip,))
|
||||||
|
snat6_thread.daemon = True
|
||||||
|
snat6_thread.start()
|
||||||
|
except ValueError:
|
||||||
|
print os.getenv('SNAT6_TO_SOURCE') + ' is not a valid IPv6 address'
|
||||||
|
|
||||||
autopurge_thread = Thread(target=autopurge)
|
autopurge_thread = Thread(target=autopurge)
|
||||||
autopurge_thread.daemon = True
|
autopurge_thread.daemon = True
|
||||||
autopurge_thread.start()
|
autopurge_thread.start()
|
||||||
|
|
||||||
chainwatch_thread = Thread(target=checkChainOrder)
|
mailcowchainwatch_thread = Thread(target=mailcowChainOrder)
|
||||||
chainwatch_thread.daemon = True
|
mailcowchainwatch_thread.daemon = True
|
||||||
chainwatch_thread.start()
|
mailcowchainwatch_thread.start()
|
||||||
|
|
||||||
signal.signal(signal.SIGTERM, quit)
|
signal.signal(signal.SIGTERM, quit)
|
||||||
atexit.register(clear)
|
atexit.register(clear)
|
||||||
|
|
|
@ -23,9 +23,14 @@ if [[ -f mailcow.conf ]]; then
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$MAILCOW_HOSTNAME" ]; then
|
while [ -z "${MAILCOW_HOSTNAME}" ]; do
|
||||||
read -p "Hostname (FQDN - example.org is not a valid FQDN): " -ei "mx.example.org" MAILCOW_HOSTNAME
|
read -p "Hostname (FQDN): " -ei "mx.example.org" MAILCOW_HOSTNAME
|
||||||
fi
|
DOTS=${MAILCOW_HOSTNAME//[^.]};
|
||||||
|
if [ ${#DOTS} -lt 2 ]; then
|
||||||
|
echo "${MAILCOW_HOSTNAME} is not a FQDN"
|
||||||
|
MAILCOW_HOSTNAME=
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
if [[ -a /etc/timezone ]]; then
|
if [[ -a /etc/timezone ]]; then
|
||||||
TZ=$(cat /etc/timezone)
|
TZ=$(cat /etc/timezone)
|
||||||
|
@ -122,9 +127,12 @@ IPV4_NETWORK=172.22.1
|
||||||
# Internal IPv6 subnet in fc00::/7
|
# Internal IPv6 subnet in fc00::/7
|
||||||
IPV6_NETWORK=fd4d:6169:6c63:6f77::/64
|
IPV6_NETWORK=fd4d:6169:6c63:6f77::/64
|
||||||
|
|
||||||
# Use this IP for outgoing connections (SNAT)
|
# Use this IPv4 for outgoing connections (SNAT)
|
||||||
#SNAT_TO_SOURCE=
|
#SNAT_TO_SOURCE=
|
||||||
|
|
||||||
|
# Use this IPv6 for outgoing connections (SNAT)
|
||||||
|
#SNAT6_TO_SOURCE=
|
||||||
|
|
||||||
# Disable IPv6
|
# Disable IPv6
|
||||||
# mailcow-network will still be created as IPv6 enabled, all containers will be created
|
# mailcow-network will still be created as IPv6 enabled, all containers will be created
|
||||||
# without IPv6 support.
|
# without IPv6 support.
|
||||||
|
|
|
@ -48,6 +48,7 @@ CONFIG_ARRAY=(
|
||||||
"IPV6_NETWORK"
|
"IPV6_NETWORK"
|
||||||
"LOG_LINES"
|
"LOG_LINES"
|
||||||
"SNAT_TO_SOURCE"
|
"SNAT_TO_SOURCE"
|
||||||
|
"SNAT6_TO_SOURCE"
|
||||||
"SYSCTL_IPV6_DISABLED"
|
"SYSCTL_IPV6_DISABLED"
|
||||||
"COMPOSE_PROJECT_NAME"
|
"COMPOSE_PROJECT_NAME"
|
||||||
"SQL_PORT"
|
"SQL_PORT"
|
||||||
|
@ -125,9 +126,15 @@ for option in ${CONFIG_ARRAY[@]}; do
|
||||||
elif [[ ${option} == "SNAT_TO_SOURCE" ]]; then
|
elif [[ ${option} == "SNAT_TO_SOURCE" ]]; then
|
||||||
if ! grep -q ${option} mailcow.conf; then
|
if ! grep -q ${option} mailcow.conf; then
|
||||||
echo "Adding new option \"${option}\" to mailcow.conf"
|
echo "Adding new option \"${option}\" to mailcow.conf"
|
||||||
echo '# Use this IP for outgoing connections (SNAT)' >> mailcow.conf
|
echo '# Use this IPv4 for outgoing connections (SNAT)' >> mailcow.conf
|
||||||
echo "#SNAT_TO_SOURCE=" >> mailcow.conf
|
echo "#SNAT_TO_SOURCE=" >> mailcow.conf
|
||||||
fi
|
fi
|
||||||
|
elif [[ ${option} == "SNAT6_TO_SOURCE" ]]; then
|
||||||
|
if ! grep -q ${option} mailcow.conf; then
|
||||||
|
echo "Adding new option \"${option}\" to mailcow.conf"
|
||||||
|
echo '# Use this IPv6 for outgoing connections (SNAT)' >> mailcow.conf
|
||||||
|
echo "#SNAT6_TO_SOURCE=" >> mailcow.conf
|
||||||
|
fi
|
||||||
elif ! grep -q ${option} mailcow.conf; then
|
elif ! grep -q ${option} mailcow.conf; then
|
||||||
echo "Adding new option \"${option}\" to mailcow.conf"
|
echo "Adding new option \"${option}\" to mailcow.conf"
|
||||||
echo "${option}=n" >> mailcow.conf
|
echo "${option}=n" >> mailcow.conf
|
||||||
|
|
Loading…
Reference in New Issue