136 lines
5.5 KiB
Python
136 lines
5.5 KiB
Python
import email
|
|
import logging
|
|
import psycopg2
|
|
import requests
|
|
import smtplib
|
|
import time
|
|
import yaml
|
|
from bs4 import BeautifulSoup
|
|
from datetime import datetime
|
|
|
|
config = yaml.full_load(open("config.yaml"))
|
|
pgconn = psycopg2.connect(dbname=config["dbname"], user=config["dbuser"], password=config["dbpassword"], host=config["dbhost"])
|
|
key = config["dronebl_key"]
|
|
entries_to_remove = []
|
|
smtp_connection = smtplib.SMTP(config["email_host"], config["email_port"])
|
|
smtp_connection.starttls()
|
|
smtp_connection.login(config["email_username"], config["email_password"])
|
|
debug_log = logging.getLogger("dronebl_check_tickets")
|
|
debug_log.setLevel(logging.DEBUG)
|
|
debug_log_file_handler = logging.FileHandler("dronebl_check_tickets_debug.log")
|
|
debug_log_file_handler.setLevel(logging.DEBUG)
|
|
debug_log.addHandler(debug_log_file_handler)
|
|
debug_log.debug(f"Current run at {datetime.now()}")
|
|
|
|
s = requests.Session()
|
|
headers = {"User-Agent": config["user_agent"]}
|
|
|
|
def send_active_email(ticket, details, comment):
|
|
msg = email.message.EmailMessage()
|
|
msg["From"] = config["email_from"]
|
|
msg["Date"] = email.utils.localtime()
|
|
if config.get("email_bcc"):
|
|
msg["Bcc"] = config["email_bcc"]
|
|
msg["Message-ID"] = email.utils.make_msgid(domain=config["email_domain"])
|
|
msg["To"] = ticket["email"]
|
|
msg["Subject"] = f"DroneBL removal request for {ticket['ip']} denied"
|
|
msg.set_content(config["email_active"].format(ticket["ip"], details, comment))
|
|
smtp_connection.send_message(msg)
|
|
|
|
def send_inactive_email(ticket, comment):
|
|
msg = email.message.EmailMessage()
|
|
msg["From"] = config["email_from"]
|
|
msg["Date"] = email.utils.localtime()
|
|
if config.get("email_bcc"):
|
|
msg["Bcc"] = config["email_bcc"]
|
|
msg["Message-ID"] = email.utils.make_msgid(domain=config["email_domain"])
|
|
msg["To"] = ticket["email"]
|
|
msg["Subject"] = f"DroneBL entry for {ticket['ip']} removed"
|
|
msg.set_content(config["email_inactive"].format(ticket["ip"], comment))
|
|
smtp_connection.send_message(msg)
|
|
|
|
def remove_dronebl_entries(entries):
|
|
request = "\n".join(entries)
|
|
request_string = f'<?xml version="1.0"?>\n<request key="{key}">\n{request}\n</request>'
|
|
headers = {
|
|
"Content-Type": "text/xml",
|
|
"Content-Length": str(len(request_string)),
|
|
}
|
|
debug_log.debug(request_string)
|
|
r = requests.post("https://mirror1.dronebl.org/RPC2", data=request_string, headers=headers)
|
|
debug_log.debug(r.text)
|
|
|
|
def get_ticket_data():
|
|
login_form = {"ref": "https://mirror1.dronebl.org/admin/tickets", "account": config["dronebl_account_name"], "password": config["dronebl_account_password"]}
|
|
r = s.post("https://mirror1.dronebl.org/admin/login", headers=headers, data=login_form)
|
|
html = BeautifulSoup(r.text, "html5lib")
|
|
tickets = html.select(".listing2 > tbody > tr")
|
|
ticket_array = []
|
|
for ticket in tickets:
|
|
ticket_data = ticket.find_all("td")
|
|
ticket_array.append({
|
|
"ticket_id": ticket_data[0].text,
|
|
"incident_id": ticket_data[1].text,
|
|
"ip": ticket_data[2].text,
|
|
"proxy_type": ticket_data[3].text,
|
|
"port": ticket_data[4].text,
|
|
"date_submitted": ticket_data[5].text,
|
|
"name": ticket_data[6].text,
|
|
"email": ticket_data[7].text,
|
|
})
|
|
|
|
return ticket_array
|
|
|
|
with pgconn:
|
|
with pgconn.cursor() as curs:
|
|
for ticket in get_ticket_data():
|
|
ip = ticket["ip"]
|
|
curs.execute("select id,ip,port,exit_ip,status,proxy_type,last_seen,recheck from proxies where ip=%s or exit_ip=%s", (ip, ip))
|
|
should_remove = True
|
|
results = curs.fetchall()
|
|
comment = s.post("https://mirror1.dronebl.org/admin/tickets", headers=headers, data={"ajax": "comments", "id": ticket["ticket_id"]})
|
|
debug_log.debug(comment.text)
|
|
already_sent = False
|
|
for entry in results:
|
|
debug_log.debug(results)
|
|
if not entry[7]:
|
|
curs.execute("update proxies set status='unscanned', recheck=true where id=%s", (entry[0],))
|
|
debug_log.debug(f"rechecking {ip}")
|
|
should_remove = False
|
|
else if entry[4] in ["scanning", "unscanned"]:
|
|
debug_log.debug(f"IP: {ip} is {entry[4]}, skipping")
|
|
should_remove = False
|
|
else if entry[4] == "active":
|
|
should_remove = False
|
|
if entry[1] == entry[3] or entry[1] == ip:
|
|
if entry[5] in ["http", "socks5", "socks4", "httpsocks", "https"]:
|
|
details = f"{entry[1]} has an open {entry[5]} proxy on port {entry[2]}, confirmed active at {entry[6]}"
|
|
if entry[5] == "vpngate":
|
|
details = f"{entry[1]} is running an open VPNGate proxy on port {entry[2]}, confirmed active at {entry[6]}. These are heavily abused by spammers, therefore they are blocked."
|
|
else:
|
|
details = f"Confirmed open {entry[5]} proxy with an entry IP of {entry[1]}, port {entry[2]} and exit IP of {entry[3]}, confirmed active at {entry[6]}"
|
|
debug_log.debug(details)
|
|
s.post("https://mirror1.dronebl.org/admin/tickets", headers=headers, data={"ajax": "delete", "id": ticket["ticket_id"]})
|
|
if not already_sent:
|
|
send_active_email(ticket, details, comment.text)
|
|
debug_log.debug(f"Sent email: {details}")
|
|
already_sent = True
|
|
curs.execute("update proxies set recheck=false where id=%s", (entry[0],))
|
|
|
|
if should_remove:
|
|
if not results:
|
|
debug_log.debug(f"IP: {ip} is not in database")
|
|
else:
|
|
debug_log.debug(f"IP: {ip} has all inactive proxies")
|
|
incident_id = ticket["incident_id"]
|
|
entries_to_remove.append(f'<remove id="{incident_id}" />')
|
|
curs.execute("update proxies set recheck=false where ip=%s or exit_ip=%s", (ip, ip))
|
|
curs.execute("delete from dronebl where ip=%s", (ip,))
|
|
pgconn.commit()
|
|
send_inactive_email(ticket, comment.text)
|
|
time.sleep(5)
|
|
|
|
smtp_connection.quit()
|
|
if entries_to_remove:
|
|
remove_dronebl_entries(entries_to_remove)
|