User:Fstirlitz/quick and dirty geoip lookup script
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