[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.34.20.tm`
** See also **
* [how to find my own IP address]
** Code **
======
#! /usr/bin/env tclsh# Public IP library for Tcl, version 0.34.20.
# Copyright (c) 2015, -2016, 2020-2021 D. Bohdan.
# License: MIT.
package require Tcl 8.5-10
namespace eval public-ip {
package require dns
variable ready 0
variable services {
ipv4 {
akamai {
whoami.akamai.net
-server ns1-1.akamaitech.net
-type A
}
google {
o-o.myaddr.l.google.com
-server ns1.google.com
-type TXT
}
opendns {
myip.opendns.com
-server resolver1.opendns.com
-type A
} ultradns {
whoami.ultradns.net
-server pdns1.ultradns.net
-type A
}
}
}
}
# Resolve the public IP address using one service.# Usage: query ?akamai|google|opendns|ultradns?
proc public-ip::query {{service google} {protocol ipv4}} {
variable services
set service [dict get $services $protocol $service]
set id [dns::resolve \
{*}$service \
-command [namespace current]::query-ready \
]
vwait [namespace current]::ready
if {[dns::status $id] ne {ok}} {
set error [dns::error $id]
dns::cleanup $id
error $error
}
set rdata [dict get [lindex [dns::result $id] 0] rdata]
dns::cleanup $id
return $rdata
}
# Used internally by [query].
proc public-ip::query-ready token {
set [namespace current]::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}} {
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
}
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
}
======
<<categories>>Internet | Package