Posted on 04-02-2019 12:11 AM
I wrote this extension attribute to do a Geo lookup on the external IP address of our laptops. It uses the API from IPStack and stores the last recorded IP address locally, only doing a new lookup if the IP address changes. This prevents extra lookups. You can also add multiple API keys and it will randomly select one for the request.
If it returns your organisations external IP then you can customise what the extension attribute response will be, in this case I added the school name to make it easier for our support staff to see the device was on prem.
You can also specify where you want the two text files written to. /Users/Shared/ is the default location.
My sed skills could do with a little polishing, but it gets the job done :)
#!/bin/sh
# Script to get Geo location data from dyndns.org and IP Stack
# Will only check if a new IP is recorded, will update manually if school IP is detected
# Written 01/04/2019
# Jacob Curulli - ILT Manager, Tranby College
# Edit these values below
# Create an array of API keys and randomly select one to use
declare -a API=('123' '123' '123')
index=$( jot -r 1 0 $((${#API[@]} - 1)) )
APIKey=${API[index]}
# School external facing IP address
schoolIP="127.0.0.1"
# School location information
schoolLocation="Tranby College, Perth, Australia : -31.9674, 115.8621"
# File location to save text files to
fileLocation="/Users/Shared/"
#Get current IP address my DynDNS
currentIP=`curl -L -s --max-time 10 http://checkip.dyndns.org | egrep -o -m 1 '([[:digit:]]{1,3}.){3}[[:digit:]]{1,3}'`
# Read in last recorded IP address
oldIP=`cat "$fileLocation".ip.txt`
#Read in last recorded location
oldLocation=`cat "$fileLocation".location.txt`
echo "Current IP is $currentIP"
echo "Selected API Key is $APIKey"
echo "Old IP is $oldIP"
echo "Old location is $oldLocation"
if [ "$currentIP" = "$oldIP" ];
then
echo "IP's are the same nothing to do"
elif [ "$currentIP" = "$schoolIP" ];
then
# Device is at school, No need to waste an IP Stack lookup
echo "IP matches school IP, manually updating location"
echo "Writing current IP to disk - $currentIP"
echo $currentIP > "$fileLocation".ip.txt
echo "Writing current location to disk - $myLocation"
echo $myLocation > "$fileLocation".location.txt
echo "<result>$schoolLocation</result>"
else
echo "There is an IP mismatch"
# Fetch GEO location info from IPStack using IP address
myLocationInfo=`curl -L -s --max-time 10 http://api.ipstack.com/$currentIP?access_key="$APIKey"&format=0`
myCountryName=`echo $myLocationInfo | awk -F, '{print $6 }' | sed 's/.*://g' | sed 's/"//g'`
myRegionCode=`echo $myLocationInfo | awk -F, '{print $7 }' | sed 's/.*://g' | sed 's/"//g'`
myCity=`echo $myLocationInfo | awk -F, '{print $9 }' | sed 's/.*://g' | sed 's/"//g'`
myLatitude=`echo $myLocationInfo | awk -F, '{print $11 }' | sed 's/.*://g'`
myLongitude=`echo $myLocationInfo | awk -F, '{print $12 }' | sed 's/.*://g'`
myLocation=`echo "$myCity, $myCountryName : $myLatitude, $myLongitude"`
echo "Writing current IP to disk - $currentIP"
echo $currentIP > "$fileLocation".ip.txt
echo "Writing current location to disk - $myLocation"
echo $myLocation > "$fileLocation".location.txt
echo "<result>$myLocation</result>"
fi
Posted on 04-02-2019 10:44 AM
interesting, thanks! Where did you get the geo location for the school? What about multiple locations - we are a company and have multiple offices across the world and it would be nice to have them listed.
Posted on 04-02-2019 11:42 AM
Posted on 04-02-2019 12:32 PM
This a simple way as well:
curl https://ipinfo.io/ip
Posted on 04-02-2019 12:38 PM
@ryan.ball Nice! I'm keeping that one in my toolbox for later use. Nice and simple.
Posted on 04-02-2019 01:00 PM
@curullij Another way to do a portion of your script would be to resolve the IP of a hostname that is only available internally. For example, if your internal IPs are 10.X.X.X, you could do this:
#!/bin/bash
function internal_network_test () {
local domain="contoso.com"
local internalServer="internalserver.contoso.com"
echo "Performing internal network tests..."
# Test that a user's IP address is an internal IP address
addresses=$(ifconfig -a inet 2>/dev/null | sed -n -e '/127.0.0.1/d' -e '/0.0.0.0/d' -e '/inet/p' | awk '{print $2}')
for address in $addresses; do
if [[ "$address" =~ (^127.)|(^172.1[6-9].)|(^172.2[0-9].)|(^172.3[0-1].)|(^192.168.) ]]; then
echo "Internal network test (Device IP) failed."
return 1
fi
done
# Test that DNS lookups find internal addresses, not external
addresses=$(nslookup "$domain" | grep -A 1 "Name:" | grep "Address:" | awk '{print $2}')
for address in $addresses; do
if [[ ! "$address" =~ (^10.) ]]; then
echo "Internal network test (DNS Lookup) failed."
return 1
fi
done
# Test for internal connectivity via Ping
if ! ping -c 2 -o "$internalServer" &> /dev/null; then
echo "Internal network test (Ping) failed."
return 1
fi
}
if internal_network_test; then
echo "Device is internal."
# Do something here
else
echo "Device is external."
# Do something here
fi
exit 0
Posted on 04-02-2019 05:14 PM
@ryan.ball that is a great idea! I'll look at implementing that.
@mm2270 the command is currentIP=curl -L -s --max-time 10 http://checkip.dyndns.org | egrep -o -m 1 '([[:digit:]]{1,3}.){3}[[:digit:]]{1,3}'
However the command that Ryan posted is much simpler. That piece of code is a snippet from a really old project that has been reused several times. "if it aint broke...."
Posted on 04-02-2019 05:18 PM
@jwojda The script looks at the returned public IP address and then updates the location variable manually. I ran part of the script whilst at the school to get what the normal result would be.
If you had multiple locations then you could match each public IP to a manual location with a bunch of nested if statements. I'm sure there is a cleaner way to do it, perhaps with an array of IP's and then returning the array id and matching that to a second array with the location details for the public IP.