Linux, UFW, Netstat, Bash Script using Chat GP4 to protect a server

Not the best way to protect a server, but surprisingly effective as an additional service

V1 which worked out of the box;

Write a linux batch file program that i can run with a cron job, that will look at all ip addresses connected to the apache webserver, test if they are located in the uk and then add a rule using ufw to block them if they are not in the uk

#!/bin/bash

# Define the Apache access log file path
LOG_FILE="/var/log/apache2/access.log"

# Temporary file to store unique IP addresses
IP_LIST="/tmp/connected_ips.txt"

# API URL for geolocation
API_URL="https://ipinfo.io"

# Extract unique IP addresses from the access log
grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' "$LOG_FILE" | sort | uniq > "$IP_LIST"

# Loop through each IP address
while read -r IP; do
    # Skip local and private IPs
    if [[ "$IP" =~ ^(10\.|172\.16\.|192\.168\.|127\.|::1) ]]; then
        continue
    fi

    # Get geolocation information
    GEO_INFO=$(curl -s "$API_URL/$IP")
    COUNTRY=$(echo "$GEO_INFO" | grep -oP '"country":\s*"\K[A-Z]+')

    # Check if the country is not UK
    if [[ "$COUNTRY" != "GB" ]]; then
        echo "Blocking IP: $IP (Country: $COUNTRY)"
        # Block the IP using UFW
        ufw deny from "$IP"
    else
        echo "IP: $IP is in the UK (Country: $COUNTRY)"
    fi
done < "$IP_LIST"

# Reload UFW to apply rules
ufw reload

# Clean up temporary file
rm -f "$IP_LIST"

Instructions

  1. Save the Script: Save the script as block_non_uk_ips.sh in an appropriate directory (e.g., /usr/local/bin).
  2. Make It Executable: Run the command:bashCopyEditchmod +x /usr/local/bin/block_non_uk_ips.sh
  3. Set Up Cron Job: Open the cron configuration using:bashCopyEditcrontab -e Add the following line to run the script every hour (adjust as needed):bashCopyEdit0 * * * * /usr/local/bin/block_non_uk_ips.sh
  4. Test the Script: Run the script manually to ensure it works as expected:bashCopyEditsudo /usr/local/bin/block_non_uk_ips.sh

Notes

  1. API Usage: The script uses the ipinfo.io API, which has free and paid tiers. For heavy usage, consider getting an API key or switching to another API.
  2. UFW Configuration: Ensure UFW is installed and configured. Use sudo ufw enable if it’s not already running.
  3. Log File: Update the LOG_FILE path to match your Apache configuration if it differs.

Some adjustments to make it work using port 443 web server port

adjust the script so that countries in mainland Europe are not blocked

adjust the script so that ufw block would block an entire ip address range, for example with an ip address 189.51.32.23 the ufw statement would block 189.51.32.0/24″ and use netstat to get all the ip addresses connected to port 443

#!/bin/bash

# Temporary file to store unique IP addresses
IP_LIST="/tmp/connected_ips.txt"

# Temporary file to store already blocked subnets
BLOCKED_SUBNETS="/tmp/blocked_subnets.txt"

# API URL for geolocation
API_URL="https://ipinfo.io"

# List of mainland European country codes (ISO Alpha-2 format)
EUROPEAN_COUNTRIES=("AL" "AD" "AT" "BE" "BA" "BG" "HR" "CY" "CZ" "DK" "EE" "FI" "FR" "DE" "GR" "HU" "IS" "IE" "IT" "LV" "LI" "LT" "LU" "MT" "MC" "ME" "NL" "NO" "PL" "PT" "RO" "SM" "RS" "SK" "SI" "ES" "SE" "CH" "TR" "VA")

# Ensure the blocked subnets file exists
touch "$BLOCKED_SUBNETS"

# Use netstat to get all IP addresses connected to port 443
netstat -tn | awk '$4 ~ /:443$/ {print $5}' | cut -d':' -f1 | sort | uniq > "$IP_LIST"

# Loop through each IP address
while read -r IP; do
    # Skip local and private IPs
    if [[ "$IP" =~ ^(10\.|172\.16\.|192\.168\.|127\.|::1) ]]; then
        continue
    fi

    # Calculate the /24 subnet
    SUBNET=$(echo "$IP" | sed 's/\.[0-9]*$/\.0\/24/')

    # Skip if this subnet has already been blocked
    if grep -q "^$SUBNET$" "$BLOCKED_SUBNETS"; then
        continue
    fi

    # Get geolocation information
    GEO_INFO=$(curl -s "$API_URL/$IP")
    COUNTRY=$(echo "$GEO_INFO" | grep -oP '"country":\s*"\K[A-Z]+')

    # Check if the country is not in the UK or mainland Europe
    if [[ "$COUNTRY" != "GB" && ! " ${EUROPEAN_COUNTRIES[@]} " =~ " $COUNTRY " ]]; then
        echo "Blocking subnet: $SUBNET (Country: $COUNTRY)"
        # Block the subnet using UFW
        ufw deny from "$SUBNET"

        # Add the subnet to the blocked list
        echo "$SUBNET" >> "$BLOCKED_SUBNETS"
    else
        echo "IP: $IP is allowed (Country: $COUNTRY)"
    fi
done < "$IP_LIST"

# Reload UFW to apply rules
ufw reload

# Clean up temporary file
rm -f "$IP_LIST"
To top