Ask the right questions and you’ll get helpful answers. Ask some code if an IP exists within the CIDR range and the brief answer can be powerful.
Services like munki, reposado, or other internal offering in your company can be replicated out to other locations but if the client settings never change they’ll continue to use the original settings even if the computer is in a different office across the country. That can be expensive in time and bandwidth — if there is inter-office connectivity at all. Every computer on the network gets an IP, and every IP is in a CIDR range. Why not use that information to help.
You can determine where a computer is based on your documented CIDR ranges and checking if the current IP is in one of those ranges. Systematically processing that information can help with the task of re-configuring based on locale. A simple boolean answer can be parsed to mean anything for your environment. It’s what you do with that answer that makes the difference.
First, you need to know what CIDR ranges are active in your company’s network. Whoever setup the network should be able to provide that information. Be sure to double check the translation of CIDR to IP ranges. There is a site that can translate CIDR to the IP range. I had a few instances of CIDRs provided were overlapping and caused unexpected results when certain IPs were used.
Next, figure out what information you want returned. For my implementation I went the simple route and have the script return a single value that signifies which company office the IP is in. You can have it return as much as you want and make it as complex as you want.
The following perl code returns true if a supplied IP exists in a supplied CIDR range.
#!/usr/bin/perl use Net::CIDR::Lite; use Getopt::Std; #"i"P address and "c"IDR notated range getopt ('ic'); my $cidr = Net::CIDR::Lite->new; $cidr->add($opt_c); print "true\n" if $cidr->find($opt_i);
The following script iterates thru the known company CIDR ranges with the current computer’s IP address and sends those two pieces of information to the perl script until a match is found. When the IP exists inside a site’s CIDR range it will return the value of the site.
#!/bin/bash # To use this in other scripts reference it by # /Library/Management/Scripts/cidr/cidr-check.sh [ -i ip_address ] # # If no IP is provided by the -i argument the current IP on the computer the script is being run on will be used. # # Site Return Value # # Des Moines DSM # New York NY # Chicago CHI ############################################################### #Locations of helper scripts scriptLocation=/Library/Management/Scripts/cidr/ cidrCheckScript=check_IP_and_CIDR.pl activeiface=`route get google.com | awk '/interface/ {print $2}'` #Get the current IP address #Read in the arguments usage="Usage: cidr-check.sh [-h] [-i ip_address]" while getopts i:h flag do case "$flag" in i ) ip="$OPTARG";; h ) echo $usage exit 1;; * ) echo $usage exit 1;; esac done #Shift out the switches and arguments, leaving the actual #variables we're operating against shift $(($OPTIND - 1)) if [ -z $ip ] then ip=`/sbin/ifconfig $activeiface | /usr/bin/awk '/inet / {print $2}'` fi #Flag to mark whether the IP has been found ipFound=n ############################################################### # Lists of CIDR range names # ############################################################### dsmCidrRangeNames=(currentCIDR_DSM1 currentCIDR_DSM2) dsmCidrRangeNames_Site="DSM" chiCidrRangeNames=(currentCIDR_CHI) chiCidrRangeNames_Site="CHI" nycCidrRangeNames=(currentCIDR_NYC) nycCidrRangeNames_Site="NY" ##Eastern Time CIDR ranges #New York currentCIDR_NYC=1.2.0.0/18 ##Central Time CIDR ranges #Chicago currentCIDR_CHI=1.3.224.0/20 #Des Moines currentCIDR_DSM1=1.4.0.0/16 currentCIDR_DSM2=1.5.0.0/16 ############################################################### if [ "$ipFound" = "n" ] then for cidrRange in ${dsmCidrRangeNames[@]} do if [ "`${scriptLocation}${cidrCheckScript} -i "$ip" -c ${!cidrRange}`" = "true" ] then returnValue="${dsmCidrRangeNames_Site}" #Mark that we fnd the IP address ipFound=y #Break out of the for loop break fi done fi #CHI if [ "$ipFound" = "n" ] then for cidrRange in ${chiCidrRangeNames[@]} do if [ "`${scriptLocation}${cidrCheckScript} -i "$ip" -c ${!cidrRange}`" = "true" ] then returnValue="${chiCidrRangeNames_Site}" #Mark that we fnd the IP address ipFound=y #Break out of the for loop break fi done fi #NYC if [ "$ipFound" = "n" ] then for cidrRange in ${nycCidrRangeNames[@]} do if [ "`${scriptLocation}${cidrCheckScript} -i "$ip" -c ${!cidrRange}`" = "true" ] then returnValue="${nycCidrRangeNames_Site}" #Mark that we fnd the IP address ipFound=y #Break out of the for loop break fi done fi if [ "$ipFound" = "n" ] then #We didn't find the IP in a CIDR range /bin/echo "IP: $ip not within the specified CIDR ranges." 2>&1 exit -1 fi /bin/echo "${returnValue}" exit 0
With that information I now know what location that computer has an IP from. Those two pieces of code can be re-used as a function in any number of ways. One way we use it is to configure munki to point at the local repo for pkgs, icons, and client_resources during its preflight execution on every run. That way regardless of what office the computer is in it won’t cross the WAN to pull a pkg.
#!/bin/bash # Script to determine local site and change munki urls to local resources # Uses 'cidr-check.sh' to determine the site based on IP #Static variables munkiConfig=/Library/Preferences/ManagedInstalls cidrCheckScript=/Library/Management/Scripts/cidr/cidr-check.sh centralMunkiServer=munki.YOUR.DOMAIN.COM ################# #Check to see if we're running as root if [ `id -u` != 0 ]; then echo $0: "You must have root privileges to run this command! Exiting." exit 1 fi #Set the variable "localSite" to the returned value from 'cidr-check.sh' localSite=`"${cidrCheckScript}"` echo Local site determined to be "${localSite}" #Determining the local PackageURL to use case $localSite in DSM ) localServer=('munki-dsm.YOUR.DOMAIN.COM') ;; NY ) localServer=('munki-nyc.YOUR.DOMAIN.COM') ;; CHI ) localServer=('munki-chi.YOUR.DOMAIN.COM') ;; #All other locations should default to the central server * ) localServer=('munki-dsm.YOUR.DOMAIN.COM') ;; esac echo Local server determined to be "${localServer}" #If we can't talk to the local munki server, use the central server if ! ping -o -c 5 "${localServer}" > /dev/null 2>&1 then localServer="${centralMunkiServer}" fi #Write the local munki URLs defaults write "${munkiConfig}" PackageURL http://"${localServer}"/repo/pkgs defaults write "${munkiConfig}" IconURL http://"${localServer}"/repo/icons defaults write "${munkiConfig}" ClientResourceURL http://"${localServer}"/repo/client_resources #Write the central munki URL for everything else defaults write "${munkiConfig}" SoftwareRepoURL http://"${centralMunkiServer}"/repo #echo Converting ManagedInstalls.plist to XML, the original format of the file plutil -convert xml1 ${munkiConfig}.plist
I’m sure there are multiple ways to handle this type of problem. I’d love to hear how you handle the complexity of roaming computers and keeping configurations local.
We use this, but we leverage AD sites and services, each site in AD has a site record and in this site record is an attribute that contains the sites CIDR ie (cn=10.10.10.0/16) we check out clients IP to get the cidr, then search AD via ldapsearch for sites that have this CIDR to determine our site and thus location info. 🙂 Saves having to have additional documentation or config files as they can often become out of date quickly, especially in a large environment
Heres an example
https://github.com/hunty1/strapper/blob/master/Shell%20Script%20version/strapper.sh#L152
LikeLiked by 1 person
Interesting approach. I like the dynamic use of the existing AD setup.
LikeLike