Created
February 8, 2021 18:24
-
-
Save pcrockett/c16b4028bc81a52f5d4069ea2e7a7f76 to your computer and use it in GitHub Desktop.
Inspired by Matt's Traceroute, but more friendly for logging
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# LICENSE: GPLv3 - https://www.gnu.org/licenses/gpl-3.0.en.html | |
set -Eeuo pipefail | |
[[ "${BASH_VERSINFO[0]}" -lt 5 ]] && echo "Bash >= 5 required" && exit 1 | |
readonly DEPENDENCIES=(ping) | |
readonly SCRIPT_NAME=$(basename "${0}") | |
function show_usage() { | |
printf "Usage: %s [OPTIONS...] [TARGET]\n" "${SCRIPT_NAME}" >&2 | |
printf " -t, --ttl\t\t\tSet ping TTL\n" >&2 | |
printf " -h, --help\t\t\tShow this help message then exit\n" >&2 | |
} | |
function panic() { | |
>&2 echo "Fatal: ${*}" | |
exit 1 | |
} | |
function is_installed() { | |
command -v "${1}" >/dev/null 2>&1 | |
} | |
for dep in "${DEPENDENCIES[@]}"; do | |
is_installed "${dep}" || panic "Missing '${dep}'" | |
done | |
function is_set() { | |
# Use this like so: | |
# | |
# is_set "${VAR_NAME+x}" || show_usage_and_exit | |
# | |
# https://stackoverflow.com/a/13864829 | |
test ! -z "${1}" | |
} | |
function parse_commandline() { | |
while [ "${#}" -gt "0" ]; do | |
local consume=1 | |
case "${1}" in | |
-t|--ttl) | |
test "${#}" -gt 1 || panic "No TTL specified." | |
consume=2 | |
ARG_TTL="${2}" | |
;; | |
-h|-\?|--help) | |
ARG_HELP="true" | |
;; | |
*) | |
if is_set "${ARG_TARGET+x}"; then | |
panic "Unexpected paramter: \"${1}\"" | |
else | |
ARG_TARGET="${1}" | |
fi | |
;; | |
esac | |
shift ${consume} | |
done | |
} | |
parse_commandline "${@}" | |
if is_set "${ARG_HELP+x}"; then | |
show_usage | |
exit 1 | |
fi | |
is_set "${ARG_TTL+x}" || panic "--ttl parameter is required" | |
test "${ARG_TTL}" -gt 0 || panic "--ttl must be a number greater than 0" | |
test "${ARG_TTL}" -le 255 || panic "--ttl must be a number less than or equal to 255" | |
function ping_target() { | |
local ping_output | |
ping_output=$(ping -c 1 -W 1 -t "${2}" "${1}") | |
if [[ "${ping_output}" =~ From\ (.+)\ icmp_seq=[0-9]+\ Time\ to\ live\ exceeded ]]; then | |
echo "${BASH_REMATCH[1]}" | |
elif [[ "${ping_output}" =~ [0-9]+\ bytes\ from\ (.+): ]]; then | |
echo "${BASH_REMATCH[1]} TARGET" | |
else | |
echo "FAIL" | |
fi | |
} | |
red="\e[1;31m" | |
green="\e[1;32m" | |
reset_color="\e[0m" | |
function print_results() { | |
local color="${reset_color}" | |
if [ "${1}" == OK ]; then | |
color="${green}" | |
elif [ "${1}" == FAIL ]; then | |
color="${red}" | |
fi | |
printf "${color}%s\t%s\t%s\t%s${reset_color}\n" "${@}" | |
} | |
while true; do | |
ping_time=$(date --iso-8601=seconds) | |
ttl=1 | |
while [ "${ttl}" -le "${ARG_TTL}" ]; do | |
ip_addr="$(ping_target "${ARG_TARGET}" "${ttl}")" | |
if [ "${ip_addr}" == "FAIL" ]; then | |
print_results FAIL "${ping_time}" "ttl=${ttl}" "NA" | |
else | |
print_results OK "${ping_time}" "ttl=${ttl}" "${ip_addr}" | |
fi | |
if [[ "${ip_addr}" =~ \ TARGET$ ]]; then | |
# We have reached our target. We need to exit this while loop | |
# because we can't go further. | |
ttl="${ARG_TTL}" | |
fi | |
ttl=$((ttl + 1)) | |
done | |
sleep 1 | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment