[dbohdan] 2015-03-18: Here is my solution for how to get your globally routable IP address. It is based on [http://serverfault.com/a/560059/204338%|%this helpful answer on ServerFault] and uses the [DNS] protocol. One upside of the approach is that the DNS servers used are more likely to last and have a good uptime than your average free your-IP-over-a-[REST]-API service. Download with [wiki-reaper]: `wiki-reaper -x 44451 0 > publicip-0.2.0.tm` ====== package require Tcl 8.5 namespace eval ::public-ip { package require dns variable services { ipv4 { google {{o-o.myaddr.l.google.com} -server ns1.google.com -type TXT} akamai {whoami.akamai.net -server ns1-1.akamaitech.net -type A} opendns {myip.opendns.com -server resolver1.opendns.com -type A} } } variable ready 0 } # Resolve the public IP address using one service. # Usage: query google|akamai|opendns proc ::public-ip::query {{service google} {protocol ipv4}} { set id [::dns::resolve \ {*}[dict get ${::public-ip::services} $protocol $service]\ -command ::public-ip::query-ready] vwait ::public-ip::ready if {[::dns::status $id] ne "ok"} { error [::dns::error $id] } set result [dict get [lindex [::dns::result $id] 0] rdata] ::dns::cleanup $id return $result } # Used internally by [query]. proc ::public-ip::query-ready {token} { set ::public-ip::ready 1 } # Resolve the public IP address using all of the available services for the # selected protocol. If one of the services returns a different address than the # others generate an error. proc ::public-ip::query-all {{protocol ipv4}} { set ip "" foreach service \ [dict keys [dict get ${::public-ip::services} $protocol]] { set resolved [query $service $protocol] if {$ip eq ""} { set ip $resolved set ipResolver $service } else { if {$ip ne $resolved} { error "got $protocol address $ip from $ipResolver but\ $resolved from $service" } } } return $ip } proc ::public-ip::test {{protocol ipv4}} { puts [query-all $protocol] } # If this is the main script... if {[info exists argv0] && ([file tail [info script]] eq [file tail $argv0])} { ::public-ip::test } ====== ---- **Version for Tcl 8.6** ====== package require Tcl 8.6 namespace eval ::public-ip { package require dns variable services { ipv4 { google {{o-o.myaddr.l.google.com} -server ns1.google.com -type TXT} akamai {whoami.akamai.net -server ns1-1.akamaitech.net -type A} opendns {myip.opendns.com -server resolver1.opendns.com -type A} } } variable ready 0 # Resolve the public IP address using one service. # Usage: query google|akamai|opendns proc query {{service google} {protocol ipv4}} { variable services set id [::dns::resolve \ {*}[dict get $services $protocol $service]\ -command [namespace code query-ready]] try { vwait ::public-ip::ready if {[::dns::status $id] ne "ok"} { error [::dns::error $id] } return [dict get [lindex [::dns::result $id] 0] rdata] } finally { ::dns::cleanup $id } } # Used internally by [query]. proc query-ready {token} { variable ready 1 } # Resolve the public IP address using all of the available services for the # selected protocol. If one of the services returns a different address than the # others generate an error. proc query-all {{protocol ipv4}} { variable services set ip "" foreach service [dict keys [dict get $services $protocol]] { set resolved [query $service $protocol] if {$ip eq ""} { set ip $resolved set ipResolver $service } elseif {$ip ne $resolved} { error "got $protocol address $ip from $ipResolver but\ $resolved from $service" } } return $ip } namespace export query query-all proc test {{protocol ipv4}} { puts [query-all $protocol] } } # If this is the main script... if {[info exists argv0] && [info script] eq $argv0]} { ::public-ip::test } ====== <>Internet