#!/bin/bash

# Create a temporary directory and store its path in the TmpDir variable. 
# Set up a trap to automatically remove this directory when the script exits.
export TmpDir="$(mktemp -d)" && trap "rm -rf $TmpDir" EXIT

# Parse command-line options. 
# The script doesn't currently support any options, so it just shows a usage message if any are provided.
while getopts ":" opt; do
        case "${opt}" in
                \?) echo "Usage: $(basename $0) [<target> <port>]"; exit ;; # Show usage message and exit if an invalid option is given.
        esac
done
shift "$((OPTIND-1))"  # Shift positional parameters to handle remaining arguments after options.

# Set the target and port from the command-line arguments or prompt the user if not provided.
target="$1"
port="$2"
[[ -z "$target" ]] && read -p "Target: " target  # Prompt for target if not provided.
[[ -z "$port" ]] && read -p "Port #: " port  # Prompt for port if not provided.

# Attempt to connect to the specified target and port. 
# Timeout after 3 seconds and redirect any errors to a temporary file.
timeout 3s bash -c ': 2> >(head -1 > ${TmpDir}/err) </dev/tcp/'"${target}/${port}"

# Check the exit status of the connection attempt and provide appropriate feedback.
case $? in
        0)      echo "Open" ;;  # Connection was successful.
        124)    echo "Connection attempt timed out." ;;  # The connection attempt timed out.
        *)      ERR="$(sed 's|bash: [^:]*: ||' "${TmpDir}/err")"  # Extract the error message from the temporary file.
                case "$ERR" in
                        "Connection refused")   echo "Closed" ;;  # Connection was refused, meaning the port is closed.
                        "No route to host")     echo "Filtered" ;;  # No route to the host, likely indicating a filtered port.
                        *) echo "$ERR" ;;  # Display any other error messages.
                esac ;;
esac