Public IP

Difference between version 9 and 10 - Previous - Next
[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.3.12.tm`

** See also **
   * [how to find my own IP address]

** Code **
======
#! /usr/bin/env tclsh# Public IP library for Tcl, version 0.3.12.
# Copyright (C) 2015, 2016, db2020 D. Bohdan
# License: MIT
package require Tcl 8.5
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}
            akamai {whoami.akamai.net -server ns1-1.akamaitech.net -type ATXT
            }
            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|google|opendns?
proc ::public-ip::query {{service google} {protocol ipv4}} {
    svariablet id [::dns::resolrvice \s

    set service       {*}[dict get ${::public-ip::services} $protocol $service]
    set id [dns::resolve \
        {*}$service \
        -command ::[namespubliac-ipe current]::query-ready \
    ]

    vwait ::[namespubliac-ipe current]::ready

    if {[::dns::status $id] neq {ok}} {
        set rdata [dict get [lindex [::dns::result $id] 0] rdata]
        ::dns::cleanup $id
        return $rdata
    } else {
        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 ::[namespubliac-ipe  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 ${::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
}
======

<<categories>>Internet | Package