Поиск мак адреса на большом количестве коммутаторов…

Не так давно на работе столкнулся со следующей ситуацией — существует десяток коммутаторов второго уровня D-Link и Allied Telesys, к которым подключено несколько сотен устройств разных организаций. Периодически возникает необходимость узнать, к какому порту какого коммутатора подключен определённый пользователь. Искать вручную среди нескольких сотен MAC адресов единственный нужный — довольно трудоёмкое занятие, отнимающее драгоценное время. Те, кто знаком с подобным занятием не по наслышке порой очень хотели бы воспользоваться чем-нибудь вроде grep или хотя бы сохранить список адресов в текстовый файл, поэтому я решил автоматизировать процесс поиска MAC’ов. Единственное, что нам для этого понадобится (кроме входящих в любой дистрибутив программ grep, cat и т.д.) — утилита expect. Пользователи дистрибутивов, использующих систему управления пакетами apt, могут установить её следующим образом:

# apt-get install expect

Для начала нам понадобится скрипт (я назвал его comm) для выполнения произвольной команды на удалённом коммутаторе. Он может послужить основой для множества других скриптов, позволяющих существенно экономить время при работе с сетью. Я буду описывать принцип работы скрипта в закомментированных строках.

#!/usr/bin/expect -f
# Указываем в качестве используемой оболочки саму утилиту expect.
# Ключ -f нужен для передачи аргументов в скрипт.

set remote_server [lindex $argv 0]
# Переменной remote_server присваиваем значение первого аргумента,
# в качестве которого будем использовать IP адрес коммутатора.

set my_command [lindex $argv 1]
# Переменной my_command присваиваем значение второго аргумента,
# который будет содержать собственно выполняемую комманду

spawn telnet $remote_server
# Открываем telnet соединение с узлом, имеющим указанный IP адрес.

set fail 0
# В этой переменной будем хранить код ошибки. Если ошибок нет, её значение
# должно быть равно нулю.

expect {
	-timeout 5
	"DES" { set model "dlink" }
	"Connected to" { set model "at" }
	timeout { set fail 1 }
	}
# После попытки соединения с коммутатором, ожидаем в течение пяти секунд некоего
# ответа. В случае, если в ответе присутствует "DES" (обозначение модельного ряда
# коммутаторов D-Link), то переменной model будет присвоено значение "dlink",
# если в приветствии встречается "Connected to", то это ответ Allied Telesys и
# переменной присвоится значение "at". Это на данный момент не используется, 
# но может пригодиться в будущем, если Вы захотите модифицировать скрипт под
# свои нужды.

if ($fail) {
	exit 2
	}

expect "User*Name:"
send "adm\r"
expect "Pass*ord:"
send "PASS_HERE\r"
# D-Link и Telesis выдают различные приглашения для ввода логина и пароля. Например,
# в одном случае у нас строка UserName слитно, в другом - через пробел. После ввода 
# логина и пароля ждём решётку - это значит, что мы подключились к коммутатору с правами
# администратора. В принципе, наша задача не требует таких прав, но используя учётную 
# запись администратора, можно будет с его помощью выполнять практически любые команды. 
# Внимание! Логин и пароль от коммутатора хранятся в открытом виде, поэтому позаботьтесь 
# о правильных правах доступа для скрипта.

expect "#"
send "$my_command\r"

for  {} 1 {} {
	expect {
		-timeout 5
		"*Next Page*" { send "n" }
		"More:*space*" { send " " }
		"#" exit 0		
		}
	}

# В случае, если количество выводимых линий не помещается на экране (а при работе с mac
# адресами это скорее всгео будет так, если конечно в вашей конторе не пять рабочих станций),
# коммутатор выводит список постранично, каждый раз ожидая от пользователя либо нажатия 
# "n" в случае с D-Link, либо пробела в случае с Telesys. По завершении списка, мы возвращаемся в
# коммандный режим и снова видим на экране решётку. В этот момент мы должны остановить
# цикл вывода.

expect #

И наконец, второй скрипт.

#!/bin/bash

function search_a {
	echo =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
	echo Finding on $1...
	./comm $1 "sh br ad ad $2" | grep $2 | grep -v "sh br ad ad"
	}

# Функция запрашивает список мак адресов у коммутатора Allied Telesys. IP адрес коммутатора - 
# первый параметр, mac адрес для отсева - второй.

function search_d {
	echo =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
	echo Finding on $1...
	./comm $1 "sh fdb" | grep $2
	}

# Функция, аналогичная вышеприведённой функции, только для коммутаторов D-Link.

function mac_tr {
	s=( a b c d e f : )
	r=( A B C D E F - )
	tmp=$1
	for i in `seq 0 6`; do
		tmp=$(echo $tmp | sed "y/"${s[$i]}"/"${r[$i]}"/")
		done
	echo $tmp
	}

# Функция для перевода мак адресов к виду, который понимают коммутаторы D-Link.	
# Буквы заглавные, байты разделены минусом. Знаю, что можно было проще, но лень 
# было менять. 🙂

if [ -n "$1" ]; then

	if ping $1 -c 2;
		then 

		echo Host $1 is alive.

		mac_a="$( /usr/sbin/arp -n $1 | tail -n 1 | awk '{ print $3 }' )"
		mac_d="$( mac_tr $mac_a )"

# Пингуем хост и если он отвечает, получаем его мак адрес и преобразуем в нужный 
# нам формат. Пинг так же нужен, чтобы мак появился в arp таблице коммутатора,
# в случае, если к данному хосту давно не было обращений.

		echo =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 
		echo MAC: $mac_a

		for i in 2 3; do
			ping -c 1 $1 2>&1 > /dev/null
		        search_a 192.168.111.$i $mac_a
	        	done

# Пробегаемся по коммутаторам Telesys.

		for i in 4 5 9 10; do
			ping -c 1 $1 2>&1 > /dev/null
			search_d 192.168.111.$i $mac_d
			done

# Затем по коммутаторам D-Link.

		else
		echo Host $1 is down.
		fi
	else
	echo Usage: $0 ip_address
	fi

А вот результат работы скрипта на живой системе (коммутаторов на данный момент стало уже меньше):

corpse@corpse:~/bin$ ./macfind 192.168.23.4
PING 192.168.23.4 (192.168.23.4) 56(84) bytes of data.
64 bytes from 192.168.23.4: icmp_seq=1 ttl=128 time=2.31 ms
64 bytes from 192.168.23.4: icmp_seq=2 ttl=128 time=0.175 ms

--- 192.168.23.4 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.175/1.242/2.310/1.068 ms
Host 192.168.23.4 is alive.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
MAC: 00:1c:f0:a7:2d:f6
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Finding on 192.168.111.2...
  233      00:1c:f0:a7:2d:f6     g2    dynamic   
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Finding on 192.168.111.3...
  233      00:1c:f0:a7:2d:f6     g1    dynamic   
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Finding on 192.168.111.5...
233   kesm              00-1C-F0-A7-2D-F6  24      Dynamic
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Finding on 192.168.111.9...
233   kesm              00-1C-F0-A7-2D-F6  50      Dynamic
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Finding on 192.168.111.10...
233   kesm              00-1C-F0-A7-2D-F6  15      Dynamic

Итого: я вижу в каком влане и на каком порту у меня есть интересующий меня мак адрес. Зная, где находятся аплинки, я сразу могу определить, к какому порту физически подключена машина.

Скрипт не претендует на универсальность, он был написан под конкретную задачу и с ней вполне справляется.
Источник:http://www.permlug.org/node/5344

Запись опубликована в рубрике *Lan&Wan, *Unix,*Linux, *Сети. Добавьте в закладки постоянную ссылку.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Я не спамер This plugin created by Alexei91