소스 검색

small fixes in fetch_new_arp. Now the last_found and mac_found fields are updated for all active entries with the same mac when they are found in the device tables. Arp_found is updated only if it is present in the arp table.

Roman Dmitriev 3 달 전
부모
커밋
0a1d965a4f
3개의 변경된 파일68개의 추가작업 그리고 62개의 파일을 삭제
  1. 21 11
      scripts/eyelib/common.pm
  2. 25 3
      scripts/eyelib/database.pm
  3. 22 48
      scripts/fetch_new_arp.pl

+ 21 - 11
scripts/eyelib/common.pm

@@ -1219,26 +1219,31 @@ sub find_mac_in_subnet {
     return unless $db && defined $ip && defined $mac && $ip ne '' && $mac ne '';
 
     my $ip_subnet = get_ip_subnet($db, $ip);
-    return unless $ip_subnet && defined $ip_subnet->{ip_int_start} && defined $ip_subnet->{ip_int_stop};
+    return unless $ip_subnet
+        && exists $ip_subnet->{ip_int_start}
+        && exists $ip_subnet->{ip_int_stop};
 
-    # Безопасный параметризованный запрос
     my @t_auth = get_records_sql($db,
-        "SELECT * FROM user_auth 
-         WHERE ip_int BETWEEN ? AND ? 
-           AND mac = ? 
-           AND deleted = 0 
+        "SELECT * FROM user_auth
+         WHERE ip_int BETWEEN ? AND ?
+           AND mac = ?
+           AND deleted = 0
          ORDER BY id",
         $ip_subnet->{ip_int_start},
         $ip_subnet->{ip_int_stop},
         $mac
     );
 
+    # Если ничего не найдено — вернуть undef
     return unless @t_auth;
 
+    # Формируем результат в требуемом формате
     my $result = { count => 0, items => {} };
     for my $i (0 .. $#t_auth) {
-        $result->{count}++;
-        $result->{items}{$result->{count}} = $t_auth[$i];
+        my $row = $t_auth[$i];
+        my $n = $i + 1;
+        $result->{count} = $n;
+        $result->{items}{$n} = $row;
     }
 
     return $result;
@@ -1335,7 +1340,10 @@ sub resurrection_auth {
         if (!$ip_record_same->{mac}) {
             # Обновляем запись без MAC
             $new_record->{mac} = $mac;
-            $new_record->{dhcp} = 0 if $mac_exists && $mac_exists->{count};
+            if ($mac_exists && $mac_exists->{count}>=1) {
+                # выключаем dhcp если есть записи в этой же подсети с другим ip и этим маком
+                $new_record->{dhcp} = 0;
+                }
             if ($action =~ /^(add|old|del)$/i) {
                 $new_record->{dhcp_action} = $action;
                 $new_record->{dhcp_time}   = $timestamp;
@@ -1372,7 +1380,9 @@ sub resurrection_auth {
 
     # --- Повторная проверка ---
     $mac_exists = find_mac_in_subnet($db, $ip, $mac);
-    $new_record->{dhcp} = 0 if $mac_exists && $mac_exists->{count};
+    if ($mac_exists && $mac_exists->{count}>=1) {
+        $new_record->{dhcp} = 0 
+        }
 
     # --- Готовим полную запись ---
     $new_record->{ip_int}      = $ip_aton;
@@ -1439,7 +1449,7 @@ sub resurrection_auth {
     my $changed_msg = prepare_audit_message($db, 'user_auth', undef, $final_record , $cur_auth_id, 'insert');
     $msg .= "\n". $changed_msg;
     db_log_warning($db, $msg, $cur_auth_id);
-    sendEmail("WARN! " . get_first_line($msg), $msg . "\n" . record_to_txt($db, 'user_auth', $cur_auth_id), 1)  if $send_alert_create;
+    sendEmail("WARN! " . get_first_line($msg), $msg , 1)  if $send_alert_create;
     return $cur_auth_id;
 }
 

+ 25 - 3
scripts/eyelib/database.pm

@@ -46,6 +46,7 @@ use Text::CSV;
 our @ISA = qw(Exporter);
 
 our @EXPORT = qw(
+update_records
 get_office_subnet
 get_notify_subnet
 is_hotspot
@@ -1537,6 +1538,27 @@ return $result;
 
 #---------------------------------------------------------------------------------------------------------------
 
+sub update_records {
+    my ($db, $table, $filter, $newvalue, @filter_params) = @_;
+
+    # Получаем ID всех записей, подходящих под фильтр
+    my $uSQL = "SELECT id FROM $table WHERE $filter";
+    my @ids = get_records_sql($db, $uSQL, @filter_params);
+
+    # Если ничего не найдено — считаем успехом
+    return 1 unless @ids;
+
+    # Обновляем каждую запись по отдельности
+    for my $record (@ids) {
+        next unless ref $record eq 'HASH' && defined $record->{id};
+        update_record($db, $table, $newvalue, "id = ?", $record->{id});
+    }
+
+    return 1;
+}
+
+#---------------------------------------------------------------------------------------------------------------
+
 sub update_record {
 my ($db, $table, $record, $filter_sql, @filter_params) = @_;
 return unless $db && $table && $filter_sql;
@@ -1588,7 +1610,7 @@ for my $field (keys %$record) {
         }
     }
 
-return 1 unless $set_clause;
+return unless $set_clause;
 
 # Добавляем служебные поля
 if ($table eq 'user_auth') {
@@ -2052,8 +2074,8 @@ if ($MY_NAME!~/upgrade.pl/) {
     init_option($dbh);
     clean_variables($dbh);
     Set_Variable($dbh);
-    warn "DBI driver name: ", $dbh->{Driver}->{Name}, "\n" if ($debug);
-    warn "Full dbh class: ", ref($dbh), "\n" if ($debug);
+#    warn "DBI driver name: ", $dbh->{Driver}->{Name}, "\n" if ($debug);
+#    warn "Full dbh class: ", ref($dbh), "\n" if ($debug);
     }
 
 1;

+ 22 - 48
scripts/fetch_new_arp.pl

@@ -69,7 +69,6 @@ foreach my $row (@u_ref) {
 # Clean temporary (dynamic) user authentication records that have expired
 my $now = DateTime->now(time_zone => 'local');
 
-
 my $clear_time_str = $now->strftime('%Y-%m-%d %H:%M:%S');
 my $users_sql = "SELECT * FROM user_auth WHERE deleted = 0 AND dynamic = 1 AND end_life <= ?";
 my @users_auth = get_records_sql($dbh, $users_sql, $clear_time_str);
@@ -194,40 +193,24 @@ foreach my $arp_table (@arp_array) {
         next if (!$mac);
         next if ($mac =~ /ff:ff:ff:ff:ff:ff/i);                     # Skip broadcast MAC
         next if ($mac !~ /(\S{2}):(\S{2}):(\S{2}):(\S{2}):(\S{2}):(\S{2})/);  # Validate MAC format
-
         my $simple_mac = mac_simplify($mac);
         $ip = trim($ip);
         my $ip_aton = StrToIp($ip);
-
-        # Initialize MAC history entry
-        $mac_history{$simple_mac}{changed} = 0;
-        $mac_history{$simple_mac}{ip}      = $ip;
-        $mac_history{$simple_mac}{auth_id} = 0;
-
         # Skip IPs outside configured office networks
         next if (!$office_networks->match_string($ip));
-
-        db_log_debug($dbh, "Analyze ip: $ip mac: $mac") if ($debug);
-
+        log_debug("Analyze ip: $ip mac: $mac") if ($debug);
         my $auth_id = $users->match_string($ip);
-	
         my $arp_record;
         $arp_record->{ip}        = $ip;
         $arp_record->{mac}       = $mac;
         $arp_record->{type}      = 'arp';
         $arp_record->{ip_aton}   = $ip_aton;
         $arp_record->{hotspot}   = is_hotspot($dbh, $ip);
-
         # Attempt to resurrect or map this ARP entry to a known auth record
         my $cur_auth_id = resurrection_auth($dbh, $arp_record);
         if (!$cur_auth_id) {
-            db_log_warning($dbh, "Unknown record " . Dumper($arp_record));
-        } else {
-            $mac_history{$simple_mac}{auth_id} = $cur_auth_id;
-            $arp_record->{auth_id} = $cur_auth_id;
-            # Mark as changed if IP-to-auth mapping differs from previous state
-            if (!$auth_id || $auth_id ne $cur_auth_id) { $mac_history{$simple_mac}{changed} = 1; }
-        }
+            log_warning("Unknown record " . Dumper($arp_record)) 
+            }
     }
 }
 
@@ -243,22 +226,20 @@ foreach my $connection (@connections_list) {
 }
 
 # Build operational and full MAC-to-auth lookup tables
-my $auth_sql = "SELECT id, mac FROM user_auth WHERE mac IS NOT NULL AND deleted = 0 AND last_found >= ? ORDER BY id ASC";
+my $auth_sql = "SELECT id, mac FROM user_auth WHERE mac IS NOT NULL AND deleted = 0 AND arp_found >= ? ORDER BY id ASC";
 my @auth_list = get_records_sql($dbh, $auth_sql, $now_day);
 
 my %auth_table;
 foreach my $auth (@auth_list) {
-    next if (!$auth);
-    next if (!$auth->{mac});
+    next if (!$auth || !$auth->{mac});
     my $auth_mac = mac_simplify($auth->{mac});
     $auth_table{oper_table}{$auth_mac} = $auth->{id};
 }
 
-$auth_sql = "SELECT id, mac FROM user_auth WHERE mac IS NOT NULL AND deleted = 0 ORDER BY last_found DESC";
+$auth_sql = "SELECT id, mac FROM user_auth WHERE mac IS NOT NULL AND deleted = 0 ORDER BY arp_found DESC, id DESC";
 my @auth_full_list = get_records_sql($dbh, $auth_sql);
 foreach my $auth (@auth_full_list) {
-    next if (!$auth);
-    next if (!$auth->{mac});
+    next if (!$auth || !$auth->{mac});
     my $auth_mac = mac_simplify($auth->{mac});
     next if (exists $auth_table{full_table}{$auth_mac});
     $auth_table{full_table}{$auth_mac} = $auth->{id};
@@ -277,8 +258,7 @@ foreach my $unknown (@unknown_list) {
 }
 
 # Fetch all SNMP-enabled devices (switches, routers, etc.) for FDB discovery
-my @device_list = get_records_sql($dbh, "SELECT * FROM devices WHERE deleted = 0 AND discovery = 1 AND device_type <= 2 AND snmp_version > 0");
-
+my @device_list = get_records_sql($dbh,"SELECT * FROM devices WHERE deleted = 0 AND (device_type = 2 OR device_type = 0) AND discovery = 1 AND snmp_version > 0");
 my @fdb_array = ();
 
 # Initialize parallel manager for FDB (forwarding database) collection
@@ -435,8 +415,18 @@ foreach my $device (@device_list) {
                 : $auth_table{full_table}{$simple_mac};
 
             unless (exists $auth_table{oper_table}{$simple_mac}) {
-                db_log_debug($dbh, "MAC not found in current ARP table. Using historical auth_id: $auth_id [$simple_mac] at device $dev_name [$port]", $auth_id);
-            }
+                log_debug($dbh, "MAC not found in current ARP table. Using historical auth_id: $auth_id [$simple_mac] at device $dev_name [$port]", $auth_id);
+                }
+
+            $mac_history{$simple_mac}{auth_id} = $auth_id;
+            $mac_history{$simple_mac}{changed} = 0;
+
+            my $auth_rec;
+            $auth_rec->{last_found} = $now_str;
+            $auth_rec->{mac_found}  = $now_str;
+            #update_record($dbh, 'user_auth', $auth_rec, "id = ?", $auth_id);
+            # update ALL active ip record
+            update_records($dbh, 'user_auth', "deleted = 0 AND mac = ?", $auth_rec, $mac_splitted);
 
             if (exists $connections{$auth_id}) {
                 if ($port_id == $connections{$auth_id}{port}) {
@@ -449,18 +439,10 @@ foreach my $device (@device_list) {
                     }
                     next;
                 }
-
                 # Port changed: update connection and log
                 $connections{$auth_id}{port} = $port_id;
                 $mac_history{$simple_mac}{changed} = 1;
-                $mac_history{$simple_mac}{auth_id} = $auth_id;
-                db_log_info($dbh, "Found auth_id: $auth_id ip: $mac_history{$simple_mac}{ip} [$mac_splitted] at device $dev_name [$port]. Update connection.", $auth_id);
-
-                my $auth_rec;
-                $auth_rec->{last_found} = $now_str;
-                $auth_rec->{mac_found}  = $now_str;
-                update_record($dbh, 'user_auth', $auth_rec, "id = ?", $auth_id);
-
+                db_log_info($dbh, "Found auth_id: $auth_id mac: [$mac_splitted] at device $dev_name [$port]. Update connection.", $auth_id);
                 my $conn_rec;
                 $conn_rec->{port_id}   = $port_id;
                 $conn_rec->{device_id} = $dev_id;
@@ -468,15 +450,8 @@ foreach my $device (@device_list) {
             } else {
                 # New connection for known user
                 $mac_history{$simple_mac}{changed} = 1;
-                $mac_history{$simple_mac}{auth_id} = $auth_id;
                 $connections{$auth_id}{port} = $port_id;
-                db_log_info($dbh, "Found auth_id: $auth_id ip: $mac_history{$simple_mac}{ip} [$mac_splitted] at device $dev_name [$port]. Create connection.", $auth_id);
-
-                my $auth_rec;
-                $auth_rec->{last_found} = $now_str;
-                $auth_rec->{mac_found}  = $now_str;
-                update_record($dbh, 'user_auth', $auth_rec, "id = ?", $auth_id);
-
+                db_log_info($dbh, "Found auth_id: $auth_id mac: [$mac_splitted] at device $dev_name [$port]. Create connection.", $auth_id);
                 my $conn_rec;
                 $conn_rec->{port_id}   = $port_id;
                 $conn_rec->{device_id} = $dev_id;
@@ -519,7 +494,6 @@ foreach my $mac (keys %mac_history) {
     my $h_ip      = $mac_history{$mac}->{ip};
     my $h_auth_id = $mac_history{$mac}->{auth_id} || 0;
     next if (!$h_dev_id);
-
     my $history_rec;
     $history_rec->{device_id} = $h_dev_id;
     $history_rec->{port_id}   = $h_port_id;