mxme.py: Checking/Enabling secondary MX.
Signed-off-by: Georg <georg@lysergic.dev>
This commit is contained in:
parent
8a9fe75e61
commit
89524ab066
@ -1,5 +1,20 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
"""
|
"""
|
||||||
|
The flagship email-domain enabler and repair tool for Mailcow/PowerDNS infrastructures.
|
||||||
|
|
||||||
|
The following checks will be performed:
|
||||||
|
DNS:
|
||||||
|
- DMARC record
|
||||||
|
- DKIM record
|
||||||
|
- MX1 + MX2 records
|
||||||
|
Mail:
|
||||||
|
- MX1 domain entry
|
||||||
|
- MX2 domain entry
|
||||||
|
- MX1 DKIM keypair
|
||||||
|
|
||||||
|
If any of the checks fail, the failed operation will be written to the respective system, in addition to overwriting possibly existing DNS records with fresh DMARC/DKIM/SPF/MX records.
|
||||||
|
|
||||||
|
Created and Last modified: 15/09/2021 by Georg Pfuetzenreuter <georg@lysergic.dev>
|
||||||
"""
|
"""
|
||||||
import requests
|
import requests
|
||||||
import sys
|
import sys
|
||||||
@ -21,8 +36,10 @@ APIKEY_PDNS = os.environ.get('APIKEY_PDNS')
|
|||||||
# MAILCOW SETTINGS
|
# MAILCOW SETTINGS
|
||||||
ENDPOINT_MAILCOW = os.environ.get('ENDPOINT_MAILCOW')
|
ENDPOINT_MAILCOW = os.environ.get('ENDPOINT_MAILCOW')
|
||||||
APIKEY_MAILCOW = os.environ.get('APIKEY_MAILCOW')
|
APIKEY_MAILCOW = os.environ.get('APIKEY_MAILCOW')
|
||||||
|
ENDPOINT_MAILCOW_2 = os.environ.get('ENDPOINT_MAILCOW_2')
|
||||||
|
APIKEY_MAILCOW_2 = os.environ.get('APIKEY_MAILCOW_2')
|
||||||
|
|
||||||
if None in (ENDPOINT_PDNS, APIKEY_PDNS, ENDPOINT_MAILCOW, APIKEY_MAILCOW):
|
if None in (ENDPOINT_PDNS, APIKEY_PDNS, ENDPOINT_MAILCOW, APIKEY_MAILCOW, ENDPOINT_MAILCOW_2, APIKEY_MAILCOW_2):
|
||||||
print("Could not load environment variables. Please check your .env file.")
|
print("Could not load environment variables. Please check your .env file.")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
@ -58,7 +75,7 @@ if dnsok == False:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# MAILCOW (can I put cow emoji in comment?)
|
# MAILCOW (can I put cow emoji in comment?)
|
||||||
print("Mail: Querying domain ...")
|
print("Mail [MX1]: Querying domain ...")
|
||||||
server = ENDPOINT_MAILCOW
|
server = ENDPOINT_MAILCOW
|
||||||
api_key = APIKEY_MAILCOW
|
api_key = APIKEY_MAILCOW
|
||||||
api = '/api/v1'
|
api = '/api/v1'
|
||||||
@ -91,7 +108,38 @@ except requests.exceptions.HTTPError as err:
|
|||||||
print(err)
|
print(err)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if mailok == True and initprimary == False:
|
print("Mail [MX2]: Querying domain ...")
|
||||||
|
server2 = ENDPOINT_MAILCOW_2
|
||||||
|
api_key2 = APIKEY_MAILCOW_2
|
||||||
|
api2 = '/api/v1'
|
||||||
|
URL = server2 + get + '/domain/' + domain
|
||||||
|
try:
|
||||||
|
response = requests.get(
|
||||||
|
URL,
|
||||||
|
headers = {'accept': 'application/json', 'X-API-Key': api_key2},
|
||||||
|
)
|
||||||
|
data = response.json()
|
||||||
|
status = response.status_code
|
||||||
|
#print(data)
|
||||||
|
if 'max_new_mailbox_quota' in data:
|
||||||
|
print("Mail: Domain found.")
|
||||||
|
mail2ok = True
|
||||||
|
initsecondary = False
|
||||||
|
domain_name = data['domain_name']
|
||||||
|
relayhost = data['relayhost']
|
||||||
|
else:
|
||||||
|
mail2ok = False
|
||||||
|
initsecondary = True
|
||||||
|
print("Mail: Domain NOT found.")
|
||||||
|
dkim2ok = False
|
||||||
|
except requests.exceptions.ConnectionError as err:
|
||||||
|
print("Connection failed.")
|
||||||
|
sys.exit(1)
|
||||||
|
except requests.exceptions.HTTPError as err:
|
||||||
|
print(err)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
#if mailok == True and initprimary == False:
|
||||||
print("Mail: Querying DKIM ...")
|
print("Mail: Querying DKIM ...")
|
||||||
URL = server + get + '/dkim/' + domain
|
URL = server + get + '/dkim/' + domain
|
||||||
try:
|
try:
|
||||||
@ -155,10 +203,32 @@ try:
|
|||||||
except NameError:
|
except NameError:
|
||||||
print("DNS: No DMARC TXT record found.")
|
print("DNS: No DMARC TXT record found.")
|
||||||
dnsdmarcok = False
|
dnsdmarcok = False
|
||||||
|
for record in data.split('\n'):
|
||||||
|
if '10 3gy.de.' in record:
|
||||||
|
mxrec1 = record
|
||||||
|
try:
|
||||||
|
mxrec1
|
||||||
|
print("DNS: Found primary MX record.")
|
||||||
|
dnsmx1ok = True
|
||||||
except NameError:
|
except NameError:
|
||||||
print("DNS: Missing or faulty DKIM/DMARC records.")
|
print("DNS: Did NOT find primary MX record.")
|
||||||
|
dnsmx1ok = False
|
||||||
|
for record in data.split('\n'):
|
||||||
|
if '20 3gy.pl.' in record:
|
||||||
|
mxrec2 = record
|
||||||
|
try:
|
||||||
|
mxrec2
|
||||||
|
print("DNS: Found secondary MX record.")
|
||||||
|
dnsmx2ok = True
|
||||||
|
except NameError:
|
||||||
|
print("DNS: Did NOT find secondary MX record.")
|
||||||
|
dnsmx2ok = False
|
||||||
|
except NameError:
|
||||||
|
print("DNS: Missing or faulty records.")
|
||||||
dnsdmarcok = False
|
dnsdmarcok = False
|
||||||
dnsdkimok = False
|
dnsdkimok = False
|
||||||
|
dnsmx1ok = False
|
||||||
|
dnsmx2ok = False
|
||||||
except requests.exceptions.ConnectionError as err:
|
except requests.exceptions.ConnectionError as err:
|
||||||
print("Connection failed.")
|
print("Connection failed.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@ -166,17 +236,21 @@ except requests.exceptions.HTTPError as err:
|
|||||||
print(err)
|
print(err)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if dnsok == True and mailok == True and dkimok == True and dnsdkimok == True and dnsdmarcok == True:
|
if dnsok == True and mailok == True and dkimok == True and dnsdkimok == True and dnsdmarcok == True and dnsmx1ok == True and dnsmx2ok == True:
|
||||||
print("All good. No changes seem to be needed. Aborting.")
|
print("All good. No changes seem to be needed. Aborting.")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
else:
|
else:
|
||||||
print("Found inconsistencies:")
|
print("Found inconsistencies:")
|
||||||
print(f"DNS OK: {dnsok} - Mail OK: {mailok} - Mail DKIM OK: {dkimok} - DNS DKIM OK: {dnsdkimok} - DNS DMARC OK: {dnsdmarcok}")
|
print(f"DNS OK: {dnsok} - Mail OK: {mailok} - Mail DKIM OK: {dkimok} - DNS DKIM OK: {dnsdkimok} - DNS DMARC OK: {dnsdmarcok} - DNS MX1 OK: {dnsmx1ok} - DNS MX2 OK: {dnsmx2ok}")
|
||||||
|
try:
|
||||||
print("Will attempt a full repair if not cancelled within 5 seconds ...")
|
print("Will attempt a full repair if not cancelled within 5 seconds ...")
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print(" Cancelled!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
if initprimary == True:
|
if initprimary == True:
|
||||||
print("Mail: Initializing domain ...")
|
print("Mail [MX1]: Initializing domain ...")
|
||||||
URL = server + add + '/domain'
|
URL = server + add + '/domain'
|
||||||
payload = {
|
payload = {
|
||||||
"active": "1",
|
"active": "1",
|
||||||
@ -199,21 +273,60 @@ if initprimary == True:
|
|||||||
json = payload,
|
json = payload,
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
status = data[0]['type']
|
|
||||||
try:
|
try:
|
||||||
|
status = data[0]['type']
|
||||||
status
|
status
|
||||||
except:
|
except:
|
||||||
print("Mail Error:")
|
print("Mail [MX1] Error:")
|
||||||
print(data)
|
print(data)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if status == 'success':
|
if status == 'success':
|
||||||
print("Mail: Created domain.")
|
print("Mail [MX1]: Created domain.")
|
||||||
if status == 'danger':
|
if status == 'danger':
|
||||||
print("Mail: Failed to create domain.")
|
print("Mail [MX1]: Failed to create domain.")
|
||||||
print(data)
|
print(data)
|
||||||
#print(f"CREATION: {status}")
|
#print(f"CREATION: {status}")
|
||||||
|
|
||||||
if initprimary == True or dkimok == False:
|
if initsecondary == True:
|
||||||
|
print("Mail [MX2]: Initializing domain ...")
|
||||||
|
URL = server2 + add + '/domain'
|
||||||
|
payload = {
|
||||||
|
"active": "1",
|
||||||
|
"aliases": "20",
|
||||||
|
"backupmx": "1",
|
||||||
|
"defquota": "1024",
|
||||||
|
"description": domain + ' - Failover',
|
||||||
|
"domain": domain,
|
||||||
|
"mailboxes": "10",
|
||||||
|
"maxquota": "2048",
|
||||||
|
"quota": "5120",
|
||||||
|
"relay_all_recipients": "1",
|
||||||
|
"rl_frame": "s",
|
||||||
|
"rl_value": "10",
|
||||||
|
"restart_sogo": "0"
|
||||||
|
}
|
||||||
|
response = requests.post(
|
||||||
|
URL,
|
||||||
|
headers = {'accept': 'application/json', 'X-API-Key': api_key2, 'Content-Type': 'application/json'},
|
||||||
|
json = payload,
|
||||||
|
)
|
||||||
|
data = response.json()
|
||||||
|
try:
|
||||||
|
status = data[0]['type']
|
||||||
|
status
|
||||||
|
except:
|
||||||
|
print("Mail [MX2] Error:")
|
||||||
|
print(data)
|
||||||
|
sys.exit(1)
|
||||||
|
if status == 'success':
|
||||||
|
print("Mail [MX2]: Created domain.")
|
||||||
|
if status == 'danger':
|
||||||
|
print("Mail [MX2]: Failed to create domain.")
|
||||||
|
print(data)
|
||||||
|
#print(f"CREATION: {status}")
|
||||||
|
|
||||||
|
#if initprimary == True or dkimok == False:
|
||||||
|
if dkimok == False:
|
||||||
print("Mail: Initializing DKIM ...")
|
print("Mail: Initializing DKIM ...")
|
||||||
URL = server + add + '/dkim'
|
URL = server + add + '/dkim'
|
||||||
payload = {
|
payload = {
|
||||||
@ -340,6 +453,27 @@ else:
|
|||||||
print(status)
|
print(status)
|
||||||
print(response.json())
|
print(response.json())
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
print("DNS: Patching MX ...")
|
||||||
|
payload = {
|
||||||
|
"rrsets": [{"name": domain + ".", "type": "MX", "ttl": "3600", "changetype": "REPLACE", "records": [{"content": "10 3gy.de.", "disabled": False, "name": domain + "."}, {"content": "20 3gy.pl.", "disabled": False, "name": domain + "."}]}]
|
||||||
|
}
|
||||||
|
response = requests.patch(
|
||||||
|
URL,
|
||||||
|
headers = {'accept': 'application/json', 'X-API-Key': APIKEY_PDNS, 'Content-Type': 'application/json'},
|
||||||
|
json = payload,
|
||||||
|
)
|
||||||
|
status = response.status_code
|
||||||
|
if status == 204:
|
||||||
|
print("MX: OK!")
|
||||||
|
elif status == 422:
|
||||||
|
print("MX: Failed:")
|
||||||
|
print(response.json())
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print("Unhandled error.")
|
||||||
|
print(status)
|
||||||
|
print(response.json())
|
||||||
|
sys.exit(1)
|
||||||
print("Done.")
|
print("Done.")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user