#!/bin/bash

debug0=true  # Summary
debug1=true  # Normal debug
debug2=false # Advanced debug
searchVendor=true

# GLPI db settings
dbuser=glpi_user
export MYSQL_PWD=glpi_password
db=glpi
dbhost=db_host

# Switch user, default: admin
swUser=

# Init counters
knownMacCpt=0
totalMacCpt=0
IFS=$'\n'

# Mac address commands
CMD_CISCO="terminal length 0\nshow mac address-table | inc DYN"
CMD_3COM="display mac-address"
CMD_HP="show mac"

# Check if Rancid tool is installed on the system
if command -v hlogin >/dev/null 2>&1; then
  rancid=true
else
  rancid=false
  $debug1 && echo "
Rancid is not installed
Can't connect to switches supporting SSH interactive sessions ONLY, such as HP
To install Rancid, visit http://www.shrubbery.net/rancid/
"
  # Here's my .cloginrc that lets you connect to an HP switch with an SSH public key
  # add password * ANY_PASSWORD
  # add noenable * {1}
  # add method * {ssh}

  # Rancid could also be use to connect with telnet but beware, this is not secure"
  # You could connect to switches that don't handle SSH public key authentication
fi

# Files def
localPath=$(echo $(dirname $0))
errorFile=$localPath/error.log
vendorFile=$localPath/vendors.txt
macFile=/tmp/macList.txt

> $macFile
> $errorFile
[ ! -e $vendorFile ] && touch $vendorFile

# Get switches from db
SQLSwitchList="SELECT NE.name, L.name, UPPER(M.name) FROM glpi_networkequipments AS NE \
               LEFT JOIN glpi_locations AS L ON NE.locations_id=L.id \
               LEFT JOIN glpi_manufacturers AS M ON NE.manufacturers_id=M.id \
               LEFT JOIN glpi_networkequipmenttypes AS NET ON NE.networkequipmenttypes_id=NET.id \
               WHERE NOT NE.is_deleted
               AND NET.name='Switch' \
               ORDER BY NE.name"

SQLGetComputer="select C.name,LOWER(itemtype) \
               from glpi_networkports NP, glpi_computers C \
               where NP.items_id=C.id \
               and NP.itemtype='Computer' \
               and REPLACE(NP.mac,'-',':')="

SQLGetPrinter="select P.name,LOWER(itemtype) \
               from glpi_networkports NP, glpi_printers P \
               where NP.items_id=P.id \
               and itemtype='Printer' \
               and REPLACE(NP.mac,'-',':')="

SQLGetNetworkEquipment="select N.name,LOWER(itemtype) \
               from glpi_networkports NP, glpi_networkequipments N \
               where NP.items_id=N.id \
               and itemtype='NetworkEquipment' \
               and REPLACE(NP.mac,'-',':')="

# Get mac address list from switch
# Usage: getMacs HOST VENDOR [USERNAME]
function getMacs {
  [[ $# -lt 2 ]] && exit 1
  host=$1
  vendor=$2
  
  # Default username admin, or get in argument list
  [[ $3 ]] && username=$3 || username=admin
  
  case "$vendor" in
  CISCO)
    echo -e "$CMD_CISCO" | ssh $username@$host 2>>$errorFile | grep DYN | awk '{print $2}'
    ;;
  3COM)
    ssh $username@$host "$CMD_3COM" 2>>$errorFile | grep Learned | awk '{print $1}'
    # echo -e "$CMD_3COM" | ssh $username@$host 2>/dev/null | grep Learned | awk '{print $1}'
    # 3com don't seem to handle well multiple commands
    # Works once, then fails...
    # To work with a single command line, disable the pause on each page in the switch conf as follow
    # user-interface vty 0 4
    # screen-length 0
    ;;
  HP | HEWLETT?PACKARD)
    # echo -e "$CMD_HP" | ssh $username@$host 2>>$errorFile
    # HP support interactive SSH sessions only
    # Returns one of the following:
    # Device does not support shell request not preceded by pty request
    # exec request failed on channel 0
    #
    # Use Rancid instead
    # rancid http://www.shrubbery.net/rancid/
    if $rancid; then
      hlogin -c "$CMD_HP" $host | grep '[0-9a-f]\{6\}-[0-9a-f]\{6\}' | awk '{print $2}'
    fi
  esac
}
  
switchList=$(mysql -qBN -u $dbuser $db -h $dbhost -e "$SQLSwitchList")

for switch in $switchList; do
  # Switch name, location & Manufacturer
  switchName=$(echo $switch |cut -f1)
  switchLoc=$(echo $switch |cut -f2)
  switchManufact=$(echo $switch |cut -f3)

  $debug1 && echo Processing $switchName in $switchLoc...
  case "$switchManufact" in
  HP | HEWLETT?PACKARD)
    if ! $rancid; then
      $debug1 && echo -e "\e[31m$switchManufact needs rancid, skipping\e[0m"
      break
    fi
    # HP validated, continue to next case
    ;&
  CISCO | 3COM)
    $debug1 && echo Connecting...
    macList=$(getMacs $switchName $switchManufact $swUser)

    # Process mac address
    for mac in $macList; do
      # Convert Mac to GLPI format XX:XX:XX:XX:XX:XX
      mac=$(echo $mac | sed 's/[\:\.-]//g;s/\(..\)/\1:/g;s/:$//')
      # Check if mac in processed macs file
      grep -m 1 -q $mac $macFile
      if [ $(echo $?) -eq 0 ]; then
        $debug2 && echo $mac already processed: skipping
      else
        echo $mac >> $macFile
        ((totalMacCpt++))
        unset device
        device=$(mysql -qBN -u $dbuser $db -h $dbhost -e "($SQLGetComputer'$mac') \
                                                   UNION ($SQLGetPrinter'$mac') \
                                                   UNION ($SQLGetNetworkEquipment'$mac')")
        if [ $(echo "$device"|wc -l) -gt 1 ]; then
          # Check if multiple values for same mac
          $debug0 && echo -e "\e[31mSame mac address for\n$device\e[0m"
        elif [ -z $device ]; then
          # Mac not found in GLPI db
          if $searchVendor; then
            shortmac=$(echo $mac|cut -c1-8)
            vendor=`grep -h -m 1 ^$shortmac $vendorFile | head -n 1 | cut -d ' ' -f 2-`
            if [ -z $vendor ]; then #not in file cache
              vendor=$(wget -q -O- http://api.macvendors.com/$shortmac)
              echo $shortmac $vendor >> $vendorFile
            fi
            echo -e "\e[33m$mac unknown, by $vendor\e[0m"
          fi
        else
          # Mac found in GLPI db
          ((knownMacCpt++))
          devicename=$(echo $device | awk '{$NF=""; print $0}' | sed 's/ $//')
          devicetype=$(echo $device | awk 'NF>1{print $NF}')
          $debug1 && echo $mac found for $devicetype $devicename, updating...
          # Update device location and last update time
          mysql -qBN -u $dbuser $db -h $dbhost -e "UPDATE glpi_"$devicetype"s T \
                    JOIN glpi_networkports NP ON T.id=NP.items_id \
                    SET locations_id=(SELECT id FROM glpi_locations WHERE name='"$switchLoc"'), \
                        date_mod=now()
                    WHERE REPLACE(NP.mac,'-',':')='"$mac"'"
        fi
        $debug1 && echo
      fi
    done
    ;;
  *)
    # Unsupported switch, skipping
    $debug1 && echo -e "\e[31m$switchManufact unsupported, skipping\e[0m"
  esac
  $debug1 && echo
  $debug2 && sleep 1
done

$debug0 && echo $totalMacCpt mac processed
if [ $totalMacCpt -eq 0 ]; then
  $debug0 && echo No mac processed
else
  $debug0 && echo $(($knownMacCpt * 100 / $totalMacCpt))% mac found
fi

rm -f $macFile

exit 0

