Public IP

Difference between version 11 and 16 - 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.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