Ad Widget

Collapse

Мониторинг mac-адресов на порту коммутатора

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • MTm01
    Junior Member
    • Feb 2020
    • 3

    #1

    Мониторинг mac-адресов на порту коммутатора

    Возникла необходимость мониторить наличие маков на access портах коммутаторов, попытался сделать по мануалу с хабра: https://habr.com/ru/post/128439/
    Но что-то не получается, если запустить скрипт вручную, то создается файл с маками на портах

    Code:
    cat /tmp/172.18.0.241-getmac.tmp  
    5;00:0e:5e:08:86:8a
    2;f8:f0:82:02:60:cb
    Добавляю данные в настройках узла на нужном порту:

    Click image for larger version

Name:	zab.png
Views:	1049
Size:	37.4 KB
ID:	396666
    Но никаких данных не получаю, а файл в /tmp имеет вид 2-getmac.tmp с пустым содержимым.

    Может кто-то реализовывал данную функцию другим способом ?
    Версия zabbix 4.2, ос ubuntu 18.04
  • FOXL
    Junior Member
    • Apr 2022
    • 2

    #2
    Судя по всему, скрипт не дописан в полной мере, что бы сопоставлять mac адрес с конкретным номером порта.
    Он сопоставляет по OID который нужно сопоставить с другим OID который будет соответствовать OID интерфейса. В нынешнем виде скрипта часть сопоставлений нужно делать самостоятельно.
    (где-то в определениях могу ошибаться)

    Брать нужный OID из этого вывода
    snmpwalk -c public -v 2c hostname .1.3.6.1.2.1.31.1.1.1.1

    Сопоставлять его с этим выводом
    snmpwalk -c public -v 2c hostname .1.3.6.1.2.1.17.1.4.1.2

    И именно цифру в конце второго вывода нужно подставлять как "порт" в "ключ"

    Пример ключа:
    mac-get.pl["{HOST.CONN}","108"]

    где "108" промежуточный ID порта, взят мной для примера.


    Все команды для работы и анализа:
    Интерфейсы
    snmpwalk -c public -v 2c hostname .1.3.6.1.2.1.31.1.1.1.1

    id интерфейсов
    snmpwalk -c public -v 2c hostname .1.3.6.1.2.1.17.1.4.1.2


    Маки
    snmpwalk -c public -v 2c hostname .1.3.6.1.2.1.17.4.3.1.1

    id интерфейсов для маков
    snmpwalk -c public -v 2c hostname .1.3.6.1.2.1.17.4.3.1.2

    hostname нужно менять на имя или ip нужного свича.
    Last edited by FOXL; 21-04-2022, 12:02.

    Comment

    • FOXL
      Junior Member
      • Apr 2022
      • 2

      #3
      Всем привет! Изучение вопроса позволило добраться до истины и заставить эту историю работать, но с оговорками.
      Первое что выяснилось, что я работал с той циской, на которой по какой-то причине есть сдвиг ID порта, хотя на большинстве других цисков с которыми я взаимодействую, ID порта относящийся к маку соответствует номеру порта.
      Второе. На большинстве цисок (не всех), что бы выводить информацию по мак адресам по конкретным vlan, нужно к строке public приписывать @номер_vlan?
      Пример public@33 для 33 vlan.
      Я немного доработал скрипт, что бы можно аргументом опрашивать кокретный vlan

      Пример построения запроса в поле "Ключ" забикса для Порта 1 и 80 vlan.
      mac-get.pl["{HOST.CONN}","1","public@80"]

      Пример построения запроса в поле "Ключ" забикса свичей где не нужно указывать vlan с public. Работает так же и со свичами Mikrotik
      mac-get.pl["{HOST.CONN}","1"]

      Сам код скрипта
      Code:
      #! /usr/bin/perl
      #====================================================================
      #
      #                   QUERY MAC ADDRESSES FROM 3COM SWITCH FROM SELECTED PORT
      #====================================================================
       
       
      use strict;
      use Net::SNMP qw(snmp_dispatcher oid_lex_sort);
       
      my $show_vendor = 1;
      my $script = "/usr/share/zabbix/scripts/mac.sh -s";
      my $debug = 0;
      my $file_name = "/tmp/$ARGV[0]-$ARGV[2]-getmac.tmp";
      my $interval = 90; #refresh rate
      my $new = 0;
      my @list;
      my $write_secs = (stat($file_name))[9];
      if ($debug == 1){
              print "file $file_name updated at ", scalar(localtime($write_secs)), "\n";
      };
      if ($write_secs + $interval < time) { #file updated less then $interval seconds ago
              if ($debug == 1){print "generating new mac table \n";}
              $new = 1;
              open FH, ">$file_name" or die "can't open '$file_name': $!";
      }else {
              if ($debug == 1){print "using old mac table \n";}
              open FR, "<$file_name" or die "can't open '$file_name': $!";
              while(my $line = <FR>) {
                      chomp($line);
                      my ($p, $m) = split/;/, $line;
                      @list[$p] = "@list[$p]$m, ";
              }
      }
      #=====================================
      my $session;
      my $error;
      my $port = $ARGV[1];
      if($new == 1) {
              #=== Setup session to remote host ===
              ($session, $error) = Net::SNMP->session(
              -hostname  => $ARGV[0] || 'localhost',
              -community => $ARGV[2] || 'public',
              -version => '2c',
              -translate   => [-octetstring => 0],
              -port      => 161
              );
              #=== Was the session created? ===
              if (!defined($session)) {
                      printf("ERROR: %s\n", $error);
                      exit 1;
              }
      };
      #==================================
       
      #=== OIDs queried to retrieve information ====
      my $TpFdbAddress = '1.3.6.1.2.1.17.4.3.1.1';
      my $TpFdbPort    = '1.3.6.1.2.1.17.4.3.1.2';
      #=============================================
      my $result;
      my @tmp;
      my $x;
      if($new == 1) {
              if (defined($result = $session->get_table($TpFdbAddress))) {
                      foreach (oid_lex_sort(keys(%{$result}))) {
                              $x = unpack('H*',$result->{$_});
                              $x =~ s/(..(?!\Z))/\1:/g;
                              push( @tmp, $x);
                      }
              }else {
                      if($debug == 1) {
                              printf("ERROR: %s\n\n", $session->error());
                      }
              }
      #==========================================
      #=== Print the returned MAC ports ===
              $result;
              if (defined($result = $session->get_table(-baseoid => $TpFdbPort))) {
                      my $i = 0;
                      my $out = "";
                      my $res = 0;
                      my $tmp_port;
                      my $tmp_mac_list = "";
                      foreach (oid_lex_sort(keys(%{$result}))) {
                              if($result->{$_} == $port) {
                                      $res = 1;
                                      if( $show_vendor == 1) {
                                              $out = `$script $tmp[$i]`;
                                              printf("%s(%s)", $tmp[$i], $out);
                                      }else {
                                              printf("%s", $tmp[$i]);
                                      };
                                      print ", ";
                              };
                              if( $show_vendor == 1) {
                                      $out = `$script $tmp[$i]`;
                                      printf FH ("%s;%s(%s)\n", $result->{$_}, $tmp[$i], $out);
                              }else {
                                      printf FH ("%s;%s\n", $result->{$_}, $tmp[$i]);
                              };
                      $i++;
                      }
                      if ($res == 0) {
                              print "null-res";
                      };
              }else {
                      if($debug == 1) {
                              printf("ERROR: %s\n\n", $session->error());
                      }else {
                              print "null-debug";
                      };
              }
      }else {
              if(@list[$port]) {
                      print "@list[$port]";
              }else {
                      print "null-port";
              };
      }
      print "\n";
      #=============================================
      #=== Close the session and exit the program ===
      if($new == 1) {
              $session->close;
              close FH;
      }else {
              close FR;
      }
      exit 0;


      Важно в конфиге забикса прописать максимальный timeout 30 секунд
      Но и его к сожалению может не хватать из за большого количества адресов на транках.
      Из за чего обработка скрипта будет дропаться забиксом и tmp файле будет только
      чать mac адресов для дальнейшей обработки скриптоп по запросу из заббикса

      По этой причине этот скрипт может далеко не везде работать.
      Где нужно прописать таймаут:
      zabbix_server.conf
      Code:
      ### Option: Timeout
      #    Specifies how long we wait for agent, SNMP device or external check (in seconds).
      #
      # Mandatory: no
      # Range: 1-30
      # Default:
      #Timeout=5
      
      Timeout=30
      Еще скрипт слабо пригоден для работы, так быстро искать нужные данные в zabbix технически невозможно.
      Можно искать в самих tmp файлах, например через notpad++, но тогда для сбора данных в эти файлы, лучше делать простейший скрипт для запуска опроса на нужных устройствах и vlan.
      Так как описал выше, забик дропает выполнение скрипта если оно превышает 30 секунд.

      В идеале сделать отдельный скрипт для сбора данных и анализа минуя заббикс. А там можно будет и уведомления прикрутить о новых мак адресах, если кому надо. И данные смогут храниться в одном файле, если это будет нужно.

      Обязательно пишите, если данная информация была полезна для вас и хотите скорректировать или поблагодарить.
      Если вы делали скрипт для сбора маков в отрыве от zabbix, будет круто, если вы им поделитесь. Спасибо!

      Comment

      Working...