User:Fstirlitz/quick and dirty geoip lookup script
Appearance
in fact a wrapper around mmdblookupAUR (whose pseudo-JSON output format is, to put it mildly, fucking braindead). you also need jshon (and bash, and maybe host).
#!/bin/bash
MMDB_PATHNAME="/var/lib/geoip/GeoLite2-City.mmdb" # wiki.archlinux.org/index.php/User:Fstirlitz/geolite2_update_script
json_mode=0
show_help() {
echo "usage: $0 [-j] [-4|-6] \$ip_address"
echo " -j output JSON (real JSON, not this pseudo-JSON mmdblookup spews)"
echo " -4 resolve hostnames to IPv4 addresses only"
echo " -6 resolve hostnames to IPv6 addresses (default)"
exit 1
}
ip_mode=6
get_ip_addr() {
host "$1" | awk -v ip_mode="$ip_mode" '
/has address/ { print $4 }
/has IPv6 address/ { if (ip_mode == 6) print $5 }
' | tail -1
}
while (( $# )); do
case "$1" in
-h|--help)
show_help
;;
-j)
json_mode=1
;;
-4|--ipv4)
ip_mode=4
;;
-6|--ipv6)
ip_mode=6
;;
-*)
echo "invalid option: $1"
exit 1
;;
[0-9A-Fa-f]:*|[0-9A-Fa-f][0-9A-Fa-f]:*|[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]:*|[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]:*|::*)
ip="$1"
;;
[0-9].*|[0-9][0-9].*|[0-9][0-9][0-9].*|0x*)
ip="$1"
;;
[a-z0-9]*)
ip="$(get_ip_addr "$1")"
if -z "$ip" ; then
echo "cannot resolve '$1'"
exit 1
fi
show_ip=1
;;
esac
shift
done
lookup() {
mmdblookup -f "$MMDB_PATHNAME" -i "$1" | sed -ne '
s/<[^>]*>$// ; s/ *$// ; s/[^:{[]$/&,/ ; N ; s/,\(\n\s*[\x5d}]\)/\1/ ; s/,\n\s*$// ; P ; D'
}
has_key() {
jshon -Q "$@" >/dev/null
}
if -z "$ip" ; then
show_help
fi
json="$(lookup "$ip")"
if (( json_mode )); then
echo "$json"
else
lang=en
# for dblang in $(
# mmdblookup -f "$MMDB_PATHNAME" -v -i 0.0.0.0 2>/dev/null \
# | sed -ne 's/^\s*Languages:\s*//p' | tr - _
# ); do if \
# [[ "${LC_MESSAGES:-$LANG}" == "$dblang".*
# || "${LC_MESSAGES:-$LANG}" == "$dblang"_*.*
# || "${LC_MESSAGES:-$LANG}" == "${dblang%_*}"_*.*
# || "${LC_MESSAGES:-$LANG}" == "${dblang%_*}".*
# ]]; then
# lang="$dblang"
# fi
# done
if (( show_ip )); then
printf '%-18s : %s\n' "IP address" "$ip"
fi
if has_key -e continent <<< "$json"; then
printf '%-18s : %s [%s]\n' "Continent" \
"$(jshon <<< "$json" -e continent -e names -e "$lang" -u)" \
"$(jshon <<< "$json" -e continent -e code -u)"
fi
if has_key -e registered_country <<< "$json"; then
printf '%-18s : %s [%s]\n' "Registered country" \
"$(jshon <<< "$json" -e registered_country -e names -e "$lang" -u)" \
"$(jshon <<< "$json" -e registered_country -e iso_code -u)"
fi
if has_key -e country <<< "$json"; then
country_code="$(jshon <<< "$json" -e country -e iso_code -u)"
printf '%-18s : %s [%s]\n' "Country" \
"$(jshon <<< "$json" -e country -e names -e "$lang" -u)" \
"$country_code"
fi
if has_key -e subdivisions <<< "$json"; then
case "$country_code" in
CA)
subdiv=('Province')
;;
CZ)
subdiv=('Region' 'District')
;;
ES)
subdiv=('Community' 'Province')
;;
NL)
subdiv=('Province')
;;
PL)
subdiv=('Voivodeship')
;;
US)
subdiv=('State')
;;
*)
subdiv=('Subdivision' 'Subdivision' 'Subdivision' 'Subdivision')
;;
esac
eval "names=($(jshon <<< "$json" -e subdivisions -a -e names -e "$lang"))"
eval "codes=($(jshon <<< "$json" -e subdivisions -a -e iso_code))"
for i in `seq 0 $((${#codes[@]} - 1))`; do
printf '%-18s : %s [%s]\n' "${subdiv[$i]}" "${names[$i]}" "${codes[$i]}"
done
fi
if has_key -e city <<< "$json"; then
if postal="$(jshon -Q <<< "$json" -e postal -e code -u)"; then
postal=" ($postal)"
fi
printf '%-18s : %s%s\n' "City" \
"$(jshon <<< "$json" -e city -e names -e "$lang" -u)" \
"$postal"
fi
if has_key -e location <<< "$json"; then
if lon="$(jshon -Q <<< "$json" -e location -e longitude)"; then
if "$lon" = -* ; then
lon="${lon#-}"
lonm=W
else
lonm=E
fi
lat="$(jshon <<< "$json" -e location -e latitude)"
if "$lat" = -* ; then
lat="${lat#-}"
latm=S
else
latm=N
fi
printf '%-18s : %.1f°%s %.1f°%s\n' "Coordinates" "$lon" "$lonm" "$lat" "$latm"
fi
if tz="$(jshon -Q <<< "$json" -e location -e time_zone -u)"; then
printf '%-18s : %s\n' "Time zone" "$tz"
fi
fi
fi