whereis

Description

Returns the geographic location of a specific IP address.
For more information on using whereis in LTM, you can check Jason Rahm’s article

Syntax

As of 10.1.0, the maximum length of the returned list is 8 fields. If more than 8 fields are needed, call whereis a second time with the remaining parameters.
Note: In GTM, prior to version 10, even when the country and continent keywords are specified the list of {Continent Country} is still returned. In earlier versions just use whereis and lindex to extract the appropriate field for your use case. An example is provided below.
Note: In GTM, as of version 11.0, the ldns option can be used instead of an IP address.
Note: Prior to version 10.1, only “country” and “continent” parameters are valid.
whereis <ip> [country | continent | state | abbrev | city | zip | area_code |
   latitude | longitude | isp | org | country_cf | state_cf | city_cf | proxy_type]+

whereis <ip>

  • In GTM, returns a Tcl list containing continent followed by country code. In LTM, returns a Tcl list containing continent, country code, region name (if available), and city (if available). GTM: {Asia JP} LTM: {NA US Washington {}}

whereis <ip> country

  • Returns a string containing the two-letter country code (JP)
  • Country codes are defined in ISO-3166:
  • Country Decoding Table

whereis <ip> continent

  • Returns a string containing the continent (Asia)

whereis <ip> state

  • Returns a string containing the state (Washington)

whereis <ip> abbrev

  • Returns a string containing the state abbreviation (WA) - notice this does not work on 12.1.x BZ621374 - “abbrev” argument in “whereis” iRule returns nothing

whereis <ip> city

  • Returns a string containing the city

whereis <ip> zip

  • Returns a string containing the zip code

whereis <ip> area_code

  • Returns a string containing the area code

whereis <ip> latitude

  • Returns a string (not a floating point) containing the latitude. To convert this value to degrees, divide it by 10000.0 (include the decimal point to avert truncation of the result:

    set lat_deg [expr {[whereis [IP::client_addr] latitude] / 10000.0}]
    
    )

whereis <ip> longitude

  • Returns a string (not a floating point) containing the longitude. To convert this value to degrees, divide it by 10000.0 (include the decimal point to avert truncation of the result:

    set lon_deg [expr {[whereis [IP::client_addr] longitude] / 10000.0}]
    
    )

whereis <ip> isp

  • Returns a string containing the ISP

whereis <ip> org

  • Returns a string containing the organization

whereis <ip> country_cf

whereis <ip> state_cf

whereis <ip> city_cf

whereis <ip> proxy_type

  • Returns a string containing the proxy type, or “unknown” if no information is available.

whereis <ip> continent country state

  • Returns a list containing the continent, country and state in that order.

whereis <ip> continent ISP state latitude

  • Returns a string continent, ISP, state and latitude, in that order.

Note: Any combination or order of place parameters is valid, however only 8 values will be returned at once. Note: Some or all of these data may not be available for a given IP address. Unless otherwise specified, in such an event an empty string is returned for a string value, or a zero is returned for a numeric value. Note: Some of these data are not available unless a geographic IP database has been loaded onto your system. Please contact F5 Networks to obtain this database.

Examples

Checks the geographical location of each new DNS request, choosing “asia_pool” for requests from LDNS’s with an address homed in Asia and sending all other requests to “general_pool”:
when DNS_REQUEST {
  if {[whereis [IP::client_addr]] contains "Asia"} {
    pool asia_pool
  } else {
    pool general_pool
  }
}

Version 9.x continent / country extraction:
when DNS_REQUEST {
   log local0. "IP [IP::client_addr] is in \
      continent [lindex [whereis [IP::client_addr]] 0] and \
      country [lindex [whereis [IP::client_addr]] 1]"
}

Which logs the following:
IP x.x.x.x is in continent North America and country US

Version 10.x continent / country extraction:
when DNS_REQUEST {
   log local0. "IP [IP::client_addr] is in \
      continent [whereis [IP::client_addr] continent] \
      and country [whereis [IP::client_addr] country]"
}

Which logs the following:
IP x.x.x.x is in continent North America and country US

Procedure to convert the latitude/longitude returned integers to degrees, with example iRule calling it.
proc geoloc_mod {latitude longitude} {
  return [list [expr {$latitude / 10000.}] [expr {$longitude / 10000.}]]
}
when HTTP_REQUEST {
  set lat [whereis [IP::client_addr] latitude]
  set lon [whereis [IP::client_addr] longitude]
  if { [string is integer $lat] && [string is integer $lon] } {
    #use proc to convert geolocation from strings to degrees, store in a list
    set geoloc_deg [call geoloc_mod $lat $lon]
  }
  log local0. "Latitude: [lindex $geoloc_deg 0], Longititude: [lindex $geoloc_deg 1]"
}

Version 10.1 LTM:
when CLIENT_ACCEPTED {
   log local0. "Got client: [whereis [IP::client_addr] country continent state city zip]"
}

Version 10.1+ LTM country based greylisting
# ========================================================================================
# For clients coming from a country in a greylist data group,
# Limit each client IP address to 1800 concurrent connections over a 180 second window
# If the client closes the connection, the count is immediately decremented.
# Else the count is decremented after the window times out for that connection.
#
# Greylist countries must be listed in the data group as the ISO3166 2 character
# http://www.iso.org/iso/country_codes/iso_3166_code_lists/country_names_and_code_elements.htm
when RULE_INIT {

    # Max number of connections for a client over an interval
    set static::max_conns 1800

    # Timeout for still counting a connection that has not been closed yet
    set static::interval 180

    # Name of data group containing 2 character ISO3166 country codes to limit connections for
    set static::greylist_dg "greylist_country_codes_dg"

    # Syslog pool
    set static::syslog_pool "udp_syslog_pool"

    # Syslog protocol (must be exactly TCP or UDP in uppercase)
    set static::syslog_proto "UDP"
}
when CLIENT_ACCEPTED {

    # Exit the iRule and do not check the connection rate if the client is not from a greylist country
    set country [whereis [IP::client_addr] country]
    if {$country ne ""}{

        # Check if the country is not in the grelist data group
        if {[class match $country equals $static::greylist_dg]}{

            # Exit this iRule event to prevent non-greylist IPs from being limited
            return
        }
    }

    # Set a subtable name with a standard prefix and the client IP
    set tbl "connlimit:[IP::client_addr]"

    # Check if the subtable has over X entries
    if { [table keys -subtable $tbl -count] >= $static::max_conns } {

        # Send a remote syslog message using local0.notice <133>
        # see RFC 3164 Section 4.1.1 - "PRI Part" for more info
        #HSL::send [HSL::open -proto $static::syslog_proto -pool $static::syslog_pool] "<190> [info hostname] [IP::local_addr]: Hit connection limit: [IP::client_addr]"

        # Drop the connection
        # drop

        # Or apply a rateclass
        # rateclass rateclass1

    } else {

        # Add the client IP:port to the client IP-specific subtable
        #   with a max lifetime of X seconds.
        # Use a key of the client IP:port
        set key "[IP::client_addr][TCP::client_port]"
        table set -subtable $tbl $key "ignored" $static::interval
    }
}

when CLIENT_CLOSED {
    # When the client connection is closed, remove the table entry
    table delete -subtable $tbl $key
}