#!../expect -- # # gethostbyaddr a.b.c.d - translate an internet address to a FQDN, # guessing (a lot) if necessary. # Author: Don Libes, NIST # Version 4.0 # Written: January 11, 1991 # Last revised: March 21, 1996 # By default, return a FQDN (fully qualified domain name) or descriptive # string (if FQDN is not easily determinable). This is tagged with a brief # explanation of how it was determined. # # If the host part of the FQDN cannot be determined, the original IP address # is used. # # Optional arguments act as toggles: Default # -t tag names with a description of how derived. true # -v verbose. false # -r reverse names to see if they resolve back to orig IP address. true # -n query nic for a descriptive string if it begins to look like true # the FQDN may be hard to derive. # -d turn on debugging to expose underlying dialogue false # # These options and others (see below) may be set in a ~/.gethostbyaddr file # To set options from that file, use the same syntax as below. set timeout 120 ;# timeout query after this many seconds set tag 1 ;# same as -t set reverse 1 ;# same as -r set verbose 0 ;# same as -v set nic 1 ;# same as -n set debug 0 ;# same as -d log_user 0 proc usage {} { send_user "usage: gethostbyaddr \[options\] a.b.c.d\n" send_user "options meaning (all options act as toggles) default\n" send_user " -t tag with derivation description true\n" send_user " -v verbose false\n" send_user " -r reverse back to IP addr for verification true\n" send_user " -n query nic true\n" send_user " -d produce debugging output false\n" send_user "options must be separate.\n" exit } if [file readable ~/.gethostbyaddr] {source ~/.gethostbyaddr} while {[llength $argv]>0} { set flag [lindex $argv 0] switch -- $flag \ "-v" { set verbose [expr !$verbose] set argv [lrange $argv 1 end] } "-r" { set reverse [expr !$reverse] set argv [lrange $argv 1 end] } "-n" { set nic [expr !$nic] set argv [lrange $argv 1 end] } "-t" { set tag [expr !$tag] set argv [lrange $argv 1 end] } "-d" { set debug [expr !$debug] set argv [lrange $argv 1 end] debug $debug } default { break } } set IPaddress $argv if [llength $argv]!=1 usage if 4!=[scan $IPaddress "%d.%d.%d.%d" a b c d] usage proc vprint {s} { global verbose if !$verbose return send_user $s\n } # dn==1 if domain name, 0 if text (from nic) proc printhost {name how dn} { global reverse tag IPaddress if {$dn && $reverse} { set verified [verify $name $IPaddress] } else {set verified 0} if {$verified || !$reverse || !$dn} { if $tag { send_user "$name ($how)\n" } else { send_user "$name\n" } if {$verified || !$reverse} { close wait exit } } } # return 1 if name resolves to IP address proc verify {name IPaddress} { vprint "verifying $name is $IPaddress" set rc 0 spawn nslookup expect ">*" send $name\r expect { -re "\\*\\*\\* (\[^\r]*)\r" { vprint $expect_out(1,string) } timeout { vprint "timed out" } -re "Address:.*Address: (\[^\r]*)\r" { set addr2 $expect_out(1,string) if [string match $IPaddress $addr2] { vprint "verified" set rc 1 } else { vprint "not verified - $name is $addr2" } } } close wait return $rc } set bad_telnet_responses "(telnet:|: unknown).*" proc telnet_error {s} { regexp ": (.*)\r" $s dontcare msg vprint $msg } proc guessHost {guess} { global guessHost if [info exists guessHost] return set guessHost $guess } proc guessDomain {guess} { global guessDomain if [info exists guessDomain] return set guessDomain $guess } proc guessFQDN {} { global guessHost guessDomain return $guessHost.$guessDomain } ###################################################################### # first do a simple reverse nslookup ###################################################################### vprint "using nslookup" spawn nslookup expect ">*" send "set query=ptr\r" expect ">*" send "$d.$c.$b.$a.in-addr.arpa\r" expect { timeout { vprint "timed out" } -re "\\*\\*\\* (\[^\r]*)\r" { vprint $expect_out(1,string) } -re "name = (\[^\r]*)\r" { set host $expect_out(1,string) printhost $host nslookup 1 # split out hostname from FQDN as guess for later guessHost [lindex [split $host "."] 0] } } close wait ###################################################################### # next telnet to host and ask it what its name is ###################################################################### vprint "talking smtp to $IPaddress" spawn telnet $IPaddress smtp expect { -re $bad_telnet_responses { telnet_error $expect_out(buffer) } timeout { vprint "timed out" } -re "\n220 (\[^\\. ]*).?(\[^ ]*)" { set host $expect_out(1,string) set domain $expect_out(2,string) printhost $host.$domain smtp 1 # if not valid FQDN, it's likely either host or domain if [string length $domain] { guessDomain $host.$domain } else { guessHost $host } } } catch close wait ###################################################################### # ask NIC for any info about this host ###################################################################### if {$nic || ($d == 0)} { vprint "talking to nic" spawn telnet internic.net expect { -re $bad_telnet_responses { telnet_error $expect_out(buffer) } timeout { vprint "timed out" } "InterNIC >" { send "whois\r" expect "Whois: " vprint "getting info on network $a.$b.$c" send "net $a.$b.$c\r" expect { "No match*" { vprint "no info" expect "Whois: " vprint "getting info on network $a.$b" send "net $a.$b\r" expect { "No match*" { vprint "no info" } -re "net\r\n(\[^\r]*)\r" { printhost $expect_out(1,string) nic 0 } timeout { vprint "timed out" } } } -re "net\r\n(\[^\r]*)\r" { printhost $expect_out(1,string) nic 0 } timeout { vprint "timed out" } } } } catch close wait if {$d == 0} exit } ###################################################################### # ask other hosts in the same class C what their name is # so that we can at least get the likely domain # # do this in two loops - first from current IP address down to 0 # and then next from current IP address up to 255 ###################################################################### # give up guessing host name guessHost "unknown" for {set i [expr $d-1]} {$i>0} {incr i -1} { vprint "talking smtp to $a.$b.$c.$i" spawn telnet $a.$b.$c.$i smtp expect { -re $bad_telnet_responses { telnet_error $expect_out(buffer) } timeout { vprint "timed out" } -re "\n220 (\[^\\. ]*).?(\[^ ]*)" { set host $expect_out(1,string) set domain $expect_out(2,string) printhost $guessHost.$domain "smtp - $a.$b.$c.$i is $host.$domain" 1 # if not valid FQDN, it's likely either host or domain # don't bother recording host since it can't be for # original addr. if [string length $domain] { guessDomain $host.$domain } } } catch close wait } for {set i [expr $d+1]} {$i<255} {incr i} { vprint "talking smtp to $a.$b.$c.$i" spawn telnet $a.$b.$c.$i smtp expect { -re $bad_telnet_responses { telnet_error $expect_out(buffer) } timeout { vprint "timed out" } -re "\n220 (\[^ ]*.(\[^ ])) " { set host $expect_out(1,string) set domain $expect_out(2,string) printhost $guessHost.$domain "smtp - $a.$b.$c.$i is $host.$domain" 1 # if not valid FQDN, it's likely either host or domain # don't bother recording host since it can't be for # original addr. if [string length $domain] { guessDomain $host.$domain } } } catch close wait } ###################################################################### # print our best guess as to the name ###################################################################### # How pathetic. Print something, anything! if {!$verbose && !$tag} {send_user [guessFQDN]}