Python : Check Connectivity using PAC files


I would like to start by saying in the modern century there should be absolutely no use for PAC files, however, depending on your drawn, you may find yourself coming across these old-fashioned inefficient, and archaic way to deliver the Internet, however sometimes its the "only" or "least recommended option"

PAC files are old

They use very old technology and essentially how they work if you have a list of variables that every web request goes through that list and when the web request is happy with the proxy defining that variable he uses that proxy, once you get a policy that matches, the rest of the file is completely ignored.

PAC file are inconsistent

You will also notice if you’re using these, you will have very interesting abnormalities for example, if you specify three individual proxy servers in an array, you will notice that it only ever uses the first one unless it’s completely down in which case it will move onto the second and then the third, there is no health checking in one of these configuration files so essentially if your first defined proxy is online - even if it’s not healthy, all traffic will be sent to it.

PAC file are "clunky and slow"

The final problems with the PAC file is that the larger rate gets the slower it gets, remember, every single Web request has to go through this file so if you have a website with lots of images and complicated graphics that website will get slower and slower the larger the configuration file gets - Obviously not inhuman noticeable performance differences, but it will add additional milliseconds where you don’t need them.

PAC file are used hidden on other applications.

I would also like to add the depending on the proxy platform you are using you may actually be using these PAC files and not know about it, they are a legacy configuration document that the industry seems to have trouble letting go of, It would be more logical to use WPAD (That has its own security problems, but it’s a lot more efficient than a PAC file)

Mission Control : Back to Mission parameters

Anyway, I digress, let’s go back to the original requirement, which was a nice script to check the PAC file, then to pass that configuration document and then try to get more website using it, If we can visit the website to script terminates.

Alerting for failure, built into the script.

However, if we are not able to get to the website, it will then send email alerting you the fact it cannot get to the Internet, obviously, in my example, I have scheduled this to run every five minutes, but I do not want an email every five minutes, telling me the Internet doesn’t work, So I’ve built a timer function so it will only email you once every 30 minutes to avoid excessive emails.

The content of email can be specified within the script, but it’s probably best to keep it Basic as most the time the people receiving the alerts are not always technical.

The script

import smtplib
import requests
from datetime import datetime, timedelta
from pypac import PACSession, get_pac
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

# Configuration
url_to_visit = "http://www.google.com"
pac_file_url = "https://bear.local/oldskool_pacfile.pac"
sender_email = "alert@pokebearswithsticks.com"
receiver_emails = ["lee@pokebearswithsticks.com", "alert.inbox@pokebearswithsticks.com"]  # Add more emails as needed
email_subject = "PAC File Proxy Access Alert"
smtp_server = "smtprelay.stwater.intra"
smtp_port = 25

# Global variable to track the last email sent time
last_email_time = datetime.min
def send_failure_email(error_message):
    global last_email_time
    now = datetime.now()
    # Only send an email if 30 minutes have passed since the last email
    if now - last_email_time >= timedelta(minutes=30):
        message = MIMEMultipart()
        message["From"] = sender_email
        message["To"] = ", ".join(receiver_emails)
        message["Subject"] = email_subject
        body = f"The request to visit the URL using the PAC file failed. Error: {error_message}"
        message.attach(MIMEText(body, "plain"))

        try:
            server = smtplib.SMTP(smtp_server, smtp_port)
            server.sendmail(sender_email, receiver_emails, message.as_string())
            server.quit()
           last_email_time = now
            print("Failure email sent successfully")
        except Exception as e:
            print(f"Failed to send email: {e}")

def visit_url_with_pac():
    try:
        print(f"Retrieving PAC file from {pac_file_url}")
        pac = get_pac(pac_file_url)
        if not pac:
            raise ValueError("Failed to retrieve PAC file or PAC file is empty"
        print("PAC file retrieved successfully, creating PAC session")
        session = PACSession(pac)
        print(f"Attempting to visit {url_to_visit} using the PAC file")
        response = session.get(url_to_visit)
        response.raise_for_status()
        print(f"Successfully visited {url_to_visit}")
    except Exception as e:
        error_message = str(e)
        print(f"Failed to visit {url_to_visit}: {error_message}")
        send_failure_email(error_message)
if __name__ == "__main__":
    visit_url_with_pac()

The Script Output

When the script is run it will give you a verbose output of what it is doing, here you are see it checking https://portal.azure.com not the Google in the script.


Automating the script

If you wish to automate the script, You can follow a couple of steps and you can absolutely accomplish that, first, we need to make the script executable with this:

chmod +x check_pac.py

Then, in this instance, we need to edit Cromtab Which handles are automated process execution, So to edit that file use this command:

crontab -e

Then we need to add the script within an execution of every five minutes, that would look something like this:

*/5 * * * * /var/python/python3 /home/mooney/pac-check/check_pac.py
Previous Post Next Post

Ω†Ω…ΩˆΨ°Ψ¬ Ψ§Ω„Ψ§ΨͺΨ΅Ψ§Ω„