Skip to content

Instantly share code, notes, and snippets.

@rsvp
Created February 14, 2012 06:26
Show Gist options
  • Save rsvp/1824255 to your computer and use it in GitHub Desktop.
Save rsvp/1824255 to your computer and use it in GitHub Desktop.
digy.sh : tame DNS utility dig with reasonable options. Linux bash HOWTO use dig script, get WAN public IP address, check local network status, and contact who is behind sites.
#!/usr/bin/env bash
# bash 4.1.5(1) Linux Ubuntu 10.04 Date : 2012-02-17
#
# _______________| digy : tame DNS utility dig with reasonable options.
#
# Usage: digy [address] [rev|name|short|mail|all|long|longa|who]
#
# Examples: % digy friendfeed.com
# 69.63.180.52
# # default second argument is 'short'
# #
# # With no arguments whatsoever, digy outputs
# # your public WAN IP address.
# # For LAN info: "digy local"
#
# % digy 69.63.180.52 rev
# friendfeed-reservation-02-07-snc1.facebook.com.
# # 'rev' for reverse lookup of IPv4 or IPv6 notation.
# # That dot after com actually signifies root-server.
#
# % digy friendfeed.com name
# friendfeed-reservation-02-07-snc1.facebook.com.
#
# % digy friendfeed.com long
# friendfeed.com. 3325 IN A 69.63.180.52
# friendfeed.com. 144937 IN NS ns6.facebook.com.
# friendfeed.com. 144937 IN NS ns4.facebook.com.
# friendfeed.com. 144937 IN NS ns5.facebook.com.
# friendfeed.com. 144937 IN NS ns3.facebook.com.
# friendfeed.com. 144937 IN NS ns7.facebook.com.
#
# % digy friendfeed.com who
# Creation Date: 13-oct-2005
# Expiration Date: 13-oct-2019
# Administrative Contact:
# Facebook, Inc.
# 1601 Willow Road
# Menlo Park CA 94025
# [email protected] +1.6505434800 Fax: +1.6505434800
# # output was edited for this example of 'who'.
#
#
# Dependencies: dig (standard issue from package 'dnsutils' (main))
# [assuming herein non-existence of $HOME/.digrc]
# curl (only to discern your own public IP address)
# whois (with sed and awk filtering).
# CHANGE LOG LATEST version available: https://bitbucket.org/rsvp/gists/src
#
# 2012-02-17 Add convenience option 'local' as first argument for address
# which gives LAN information. Revise preamble.
# 2012-02-15 Second argument 'who' yields non-verbose domain name
# REGISTRATION RECORD, i.e. who is behind the site.
# 2012-02-14 Use 'name' instead of 'host' as second argument;
# Executing digy without any arguments will give your
# public-facing WAN IP address (not your local LAN).
# 2012-02-13 Add examples. Share digy as a gist.
# 2012-02-12 First version to tame dig for readability and error handling.
# _____ PREAMBLE_v2: settings, variables, and error handling.
#
LC_ALL=POSIX
# locale means "ASCII, US English, no special rules,
# output per ISO and RFC standards."
# Esp. use ASCII encoding for glob and sorting characters.
shopt -s extglob
# ^set extended glob for pattern matching.
set -e
# ^errors checked: immediate exit if a command has non-zero status.
set -u
# ^unassigned variables shall be errors.
# Example of default VARIABLE ASSIGNMENT: arg1=${1:-'foo'}
addr=${1:-'public'}
opt=${2:-'short'}
program=${0##*/} # similar to using basename
memf=$( mktemp /dev/shm/88_${program}_tmp.XXXXXXXXXX )
cleanup () {
# Delete temporary files, then optionally exit given status.
local status=${1:-'0'}
rm -f $memf
[ $status = '-1' ] || exit $status # thus -1 prevents exit.
} #--------------------------------------------------------------------
warn () {
# Message with basename to stderr. Usage: warn "message"
echo -e "\n !! ${program}: $1 " >&2
} #--------------------------------------------------------------------
die () {
# Exit with status of most recent command or custom status, after
# cleanup and warn. Usage: command || die "message" [status]
local status=${2:-"$?"}
cleanup -1 && warn "$1" && exit $status
} #--------------------------------------------------------------------
trap "die 'SIG disruption, but cleanup finished.' 114" 1 2 3 15
# Cleanup after INTERRUPT: 1=SIGHUP, 2=SIGINT, 3=SIGQUIT, 15=SIGTERM
#
# _______________ :: BEGIN Script ::::::::::::::::::::::::::::::::::::::::
get_publicIP () {
curl -s http://ip.appspot.com \
|| die "function get_publicIP needs to be fixed." 123
# An external observer is needed to get your own public IP address.
# Your ISP determines whether it's permanent (probably not).
# See notes at the end for alternatives.
}
case "$addr" in
# 'localhost' is a special reserved word for 127.0.0.1
'local') ifconfig -a | egrep -v 'packets:|collisions:' \
|| die "ifconfig fail." 125
# ^all kernel-resident network interfaces (LAN) shown,
# even if they are down. Trim off some details.
# E.g. eth0 is the first Ethernet interface.
# Unnecessary to proceed any further, so
cleanup ;;
'public') addr="$( get_publicIP )"
echo "$addr"
# ^in IPv4 or IPv6 notation, depends on get_publicIP.
# Then the name is revealed by the rest of this script.
opt='rev' ;;
'--help') more "$0" && cleanup ;;
'-h') more "$0" && cleanup ;;
# source is the best documentation :-)
esac
case "$opt" in
'rev') dig +short -x $addr ;;
# ^reverse lookup given IPv4 or IPv6 notation.
'name') dig +short -x $(dig +short $addr A) \
|| die "no parent, so use 'long' option." 117 ;;
# get hostname of the A record.
'short') dig +short $addr A ;;
# type: A (default), ANY, MX, SIG, etc.
'mail') dig +short $addr MX ;;
'all') dig +short $addr ANY \
|| die "too intrusive, so use 'short' option." 119 ;;
# ^short means terse answer, else use 'long' option.
'long') dig +nocmd +noquestion +nocomment +nostats $addr ANY \
|| die "too intrusive, so use 'longa' option." 121 ;;
# long gives verbose but relevant answer.
# some sites may truncate ANY refusing answer, so
'longa') dig +nocmd +noquestion +nocomment +nostats $addr A ;;
'who') whois -H $addr \
| sed -e 's/^[[:blank:]]*//' -e 's/[[:blank:]]*$//' \
-e '/^NA$/d' -e '/^Fax:$/d' -e '/^US$/d' \
-e '/^Name Server:/d' -e '/^Status:/d' \
| awk 'BEGIN { RS = "\n\n" } \
/[Cc]ontact:/ || /[Dd]ate:/ {print $0, "\n"}' ;;
# -Hide legal disclaimers, then
# sed domain name REGISTRATION record
# against nasty invisible blanks before and after
# each line. Eliminate filler info.
# awk takes the cleansed "paragraph" as record,
# and pulls out those involving CONTACT or DATE.
*) die "undefined second arg: $opt" 113 ;;
esac > $memf
# Here's what verbose +stats produces:
# ;; Query time: 132 msec
# ;; SERVER: 192.168.1.254#53(192.168.1.254)
# ;; WHEN: Sun Feb 12 13:46:05 2012
# ;; MSG SIZE rcvd: 108
# where SERVER refers to the machine which gave answers.
# Deemed irrelevant for our purposes.
fixout () {
egrep -v 'RRSIG' $memf
# ^omit these messy lines:
# RRSIG is a digital signature of the answer DNS resource record set.
}
[ -s $memf ] && fixout \
|| die "empty answer. Check argments; try 'long' or 'rev' option." 116
cleanup
# _______________ EOS :: END of Script ::::::::::::::::::::::::::::::::::::::::
# # _______________ 2012-02-14 NOTES: get_publicIP
#
# curl -s http://ip.appspot.com
# # 2012-02-14 incorporated into digy
#
# # _____ Alternative means
#
# curl -s http://icanhazip.com
# # or choose: ipv4.icanhazip.com or ipv6.icanhazip.com
# # 2011-03-27 run by Rackspace employee Major Hayden.
# # 2012-02-14 Major Hayden ([email protected])
# # +1-210-370-7667
# # PO Box 901, Cibolo, TX 78108
#
# lynx -dump checkip.dyndns.org
# # corz.org/ip
# # ip.uostas.net
#
# # google: "my ip address" yields
# # Your public IP address is 76.200.xxx.yyy
# # _____ 2011-03-03 BUG: No longer working...
# curl -s http://whatismyip.org
# lynx -dump www.whatismyip.com | grep 'Your IP'
# The first resource record in any Domain Name System (DNS) Zone file
# should be a Start of Authority (SOA) resource record.
# The SOA resource record indicates that this DNS name server
# is the best source of information for the data within this DNS domain.
# vim: set fileencoding=utf-8 ff=unix tw=78 ai syn=sh :
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment