Last active
December 14, 2020 08:42
-
-
Save zekesonxx/e3bb041884285af3c20621fb543ac9e1 to your computer and use it in GitHub Desktop.
Cloudflare IP inspection tool
This file contains hidden or 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 | |
# Cloudflare IP inspection tool | |
# GPLv3 | |
function help() { | |
cat <<HELPEOF | |
$0 [-46h] <hostname> | |
Inspects CloudFlare datacenter IPs | |
Handles 1.1.1.1/1.0.0.1 and whitelabel nameservers (like doordash.com) | |
-4 Check IPv4 IPs | |
-6 Check IPv6 IPs | |
-f Force check, even if the site doesn't seem to be using CloudFlare | |
-h Display this help text | |
HELPEOF | |
} | |
MODE="A" | |
FORCE=0 | |
# Parse inputs | |
while getopts "f46h:" opt; do | |
case "$opt" in | |
h) | |
help | |
exit 0 | |
;; | |
4) | |
MODE="A" | |
;; | |
6) | |
MODE="AAAA" | |
;; | |
f) | |
FORCE=1 | |
;; | |
*) | |
true | |
;; | |
esac | |
done | |
shift $((OPTIND-1)) | |
[ "${1:-}" = "--" ] && shift | |
if [[ "$#" -lt 1 ]]; then | |
help | |
exit 0 | |
fi | |
HOST="$1" | |
# Figure out what IPs to check | |
if [[ "$HOST" == "1.1.1.1" ]] || [[ "$HOST" == "1.0.0.1" ]]; then | |
IPS="1.1.1.1 1.0.0.1" | |
else | |
# Check that the site is actually cloudflare | |
# (or at least uses CF nameservers) | |
NAMESERVERS="$(dig +noall +answer +authority NS "$HOST")" | |
if [[ $FORCE != 1 ]] && ! (echo $NAMESERVERS | cut -f5 | grep -q -E "\.ns\.cloudflare\.com|ns[0-9]+\.cloudflare\.com"); then | |
# Let's see if it's a branded CF thing by checking the AS | |
if ! mtr -zrCc1 $(dig +short $MODE "$HOST" | tail -1) | tail -1 | cut -d, -f7 | grep -q '^AS13335$'; then | |
echo "This domain doesn't appear to have Cloudflare nameservers" | |
echo "Got answer:" | |
echo "$NAMESERVERS" | |
exit 1 | |
else | |
echo "Domain uses white label Cloudflare nameservers" | |
echo "Example: $(echo "$NAMESERVERS" | head -1 | cut -f6)" | |
fi | |
fi | |
IPS="$(dig +short $MODE "$HOST")" | |
fi | |
for ip in $IPS; do | |
# Collect an mtr output to the IP | |
# We use this to get the ping time and the AS path | |
MTR="$(mtr -zrCc1 "$ip")" | |
# Extract the details out of mtr's output | |
PING="$(echo "$MTR" | tail -1 | cut -d, -f13)" | |
ASPATH="$(echo "$MTR" | cut -d, -f7 | grep 'AS[0-9]' | uniq | tr '\n' ' ')" | |
ASLAST="$(echo "$MTR" | cut -d, -f7 | grep 'AS[0-9]' | tail -1)" | |
# Is it actually a Cloudflare IP? | |
if [[ "$ASLAST" == "AS13335" ]]; then | |
# actual CF IP | |
# lets find what colo it's in | |
if [[ "$MODE" == "AAAA" ]]; then | |
TRACE="$(curl -s "http://[$ip]/cdn-cgi/trace")" | |
else | |
TRACE="$(curl -s "http://$ip/cdn-cgi/trace")" | |
fi | |
COLO="$(echo "$TRACE" | grep 'colo=' | cut -d= -f2)" | |
else | |
# not a CF IP | |
# don't send a suspicious /cdn-cgi/trace query to it | |
COLO="NotCF" | |
fi | |
echo "$ip $COLO ${PING}ms $ASPATH" | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Handles typical users:
Handles corporate CF domains:
Handles whitelabel nameservers:
Handles non-CF IPs served by CF nameservers:
Handles not-Cloudflare gracefully: