在前端返回空行

问题描述 投票:0回答:1

我有带有前端 GUI 的 ARP 扫描仪。

它工作得很好,直到我实现了实时显示何时找到主机。 当它在网络上找到活动主机时,它会添加包含 ip 地址和 mac 地址等信息的行,但由于某种原因它开始返回空行。以前没有实时返回时它可以工作。

这是我的后端代码:

using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Text.RegularExpressions;
using System.Windows.Input;
using System.Runtime.InteropServices;
using System.Net;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.Linq;
using System.ComponentModel;

// TODO - jak navýšit čas na odpověď od stanice? Občas možná nestihne přijít odpověd, dle jiného skeneru jsou ip adresy např. dostupné
// TODO - navýšit rychlost skenování - použit více paralel tasků 
// TODO - naimplementovaet log4net
namespace NetVision.Pages.NetworkTools
{
    public partial class NetworkScan : Page
    {
        private ObservableCollection<string> Subnets { get; set; }
        private ObservableCollection<ScanResult> ScanResults { get; set; }

        // Regex pattern for subnet validation with CIDR notation
        private static readonly Regex SubnetRegex = new Regex(
            @"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$",
            RegexOptions.Compiled);

        private int _totalHosts;
        private int _scannedHosts;

        public NetworkScan()
        {
            InitializeComponent();
            cmbTypeScan.SelectedIndex = 0;
            Subnets = new ObservableCollection<string>();
            ScanResults = new ObservableCollection<ScanResult>();

            lstSubnets.ItemsSource = Subnets;
            dgScanResults.ItemsSource = ScanResults;
        }

        private void UpdateScanDescription()
        {
            if (txtScanDescription != null)
            {
                switch (cmbTypeScan.SelectedIndex)
                {
                    case 0:
                        txtScanDescription.Text = "ARP scan works only on broadcast domain!";
                        break;
                    case 1:
                        txtScanDescription.Text = "Scans TCP/UDP opened ports.";
                        break;
                    case 2:
                        txtScanDescription.Text = "Scans TCP opened ports.";
                        break;
                    case 3:
                        txtScanDescription.Text = "Scans UDP opened ports.";
                        break;
                    case 4:
                        txtScanDescription.Text = "Uses ICMP echo requests to detect hosts.";
                        break;
                    default:
                        txtScanDescription.Text = "";
                        break;
                }
            }
        }

        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
            UpdateScanDescription();
        }

        private void txtSubnet_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                AddSubnet();
                e.Handled = true;  // Prevents the ding sound
            }
        }

        private void btnAddSubnet_Click(object sender, RoutedEventArgs e)
        {
            AddSubnet();
        }

        private void AddSubnet()
        {
            string subnet = txtSubnet.Text.Trim();
            if (!string.IsNullOrWhiteSpace(subnet))
            {
                if (SubnetRegex.IsMatch(subnet))
                {
                    Subnets.Add(subnet);
                    txtSubnet.Clear();
                    HideError();
                }
                else
                {
                    ShowError("Invalid subnet format. Please use CIDR notation (e.g., 192.168.1.0/24 or 10.0.0.0/8).");
                }
            }
        }

        private void HideError()
        {
            txtErrorMessage.Text = string.Empty;
            txtErrorMessage.Visibility = Visibility.Collapsed;
        }

        private void ShowError(string message)
        {
            txtErrorMessage.Text = message;
            txtErrorMessage.Visibility = Visibility.Visible;
        }

        private void btnDeleteSubnet_Click(object sender, RoutedEventArgs e)
        {
            if (sender is Button button && button.DataContext is string subnet)
            {
                Subnets.Remove(subnet);
            }
        }

        private async void btnStartScan_ClickAsync(object sender, RoutedEventArgs e)
        {
            if (Subnets.Count > 0)
            {
                btnStartScan.IsEnabled = false;
                btnStopScan.IsEnabled = true;
                ScanResults.Clear();

                // Reset progress
                _scannedHosts = 0;
                _totalHosts = 0;
                progressGrid.Visibility = Visibility.Collapsed;

                if (cmbTypeScan.Text == "ARP Scan")
                {
                    await PerformArpScan();
                }

                btnStartScan.IsEnabled = true;
                btnStopScan.IsEnabled = false;
            }
            else
            {
                txtErrorMessage.Text = "You need to add at least one subnet to scan.";
                txtErrorMessage.Visibility = Visibility.Visible;
            }
        }

        [DllImport("iphlpapi.dll", ExactSpelling = true)]
        private static extern int SendARP(int DestIP, int SrcIP, byte[] pMacAddr, ref uint PhyAddrLen);

        private static uint macAddrLen = (uint)new byte[6].Length;

        private async Task PerformArpScan()
        {
            var allHosts = new ConcurrentBag<IPAddress>();

            foreach (var subnet in Subnets)
            {
                var hosts = GenerateIPRange(subnet);
                foreach (var host in hosts)
                {
                    allHosts.Add(host);
                }
            }

            var results = new ConcurrentBag<ScanResult>();
            _totalHosts = allHosts.Count;
            _scannedHosts = 0;

            await Dispatcher.InvokeAsync(() =>
            {
                progressGrid.Visibility = Visibility.Visible;
                scanProgressBar.Value = 0;
                scanProgressBar.Maximum = _totalHosts;
                UpdateProgressText();
                ScanResults.Clear();
            });

            await Task.Run(() =>
            {
                Parallel.ForEach(allHosts, new ParallelOptions { MaxDegreeOfParallelism = 50 }, ip =>
                {
                    var result = SendArpRequest(ip);
                    if (result != null)
                    {
                        Application.Current.Dispatcher.Invoke(() =>
                        {
                            ScanResults.Add(result);
                        });
                    }
                    Interlocked.Increment(ref _scannedHosts);
                    Application.Current.Dispatcher.Invoke(() =>
                    {
                        scanProgressBar.Value = _scannedHosts;
                        UpdateProgressText();
                    });
                });
            });

            await Dispatcher.InvokeAsync(() =>
            {
                progressGrid.Visibility = Visibility.Collapsed;
            });
        }

        private void UpdateProgressText()
        {
            progressText.Text = $"Scanning: {_scannedHosts}/{_totalHosts} hosts";
        }

        public static IEnumerable<IPAddress> GenerateIPRange(string cidrNotation)
        {
            string[] parts = cidrNotation.Split('/');
            if (parts.Length != 2)
            {
                throw new ArgumentException("Invalid CIDR notation");
            }

            if (!IPAddress.TryParse(parts[0], out IPAddress ipAddress))
            {
                throw new ArgumentException("Invalid IP address");
            }

            if (!int.TryParse(parts[1], out int subnetBits) || subnetBits < 0 || subnetBits > 32)
            {
                throw new ArgumentException("Invalid subnet mask");
            }

            uint ipCount = (uint)(1 << (32 - subnetBits));
            byte[] ipBytes = ipAddress.GetAddressBytes();
            uint startIP = (uint)((ipBytes[0] << 24) | (ipBytes[1] << 16) | (ipBytes[2] << 8) | ipBytes[3]);

            for (uint i = 0; i < ipCount; i++)
            {
                uint currentIP = startIP + i;
                byte[] currentIPBytes = new byte[4]
                {
                    (byte)(currentIP >> 24),
                    (byte)(currentIP >> 16),
                    (byte)(currentIP >> 8),
                    (byte)currentIP
                };

                yield return new IPAddress(currentIPBytes);
            }
        }

        private ScanResult SendArpRequest(IPAddress ipAddress)
        {
            byte[] macAddr = new byte[6];
            uint macAddrLen = (uint)macAddr.Length;

            try
            {
                // Convert IP address to bytes in the correct order
                byte[] ipBytes = ipAddress.GetAddressBytes();
                int ipInteger = BitConverter.ToInt32(ipBytes, 0);

                int result = SendARP(ipInteger, 0, macAddr, ref macAddrLen);

                if (result == 0)
                {
                    // Create MAC address string
                    string macAddressString = BitConverter.ToString(macAddr, 0, (int)macAddrLen).Replace("-", ":");

                    // Create and return result immediately
                    var scanResult = new ScanResult
                    {
                        IpAddress = ipAddress.ToString(),
                        MacAddress = macAddressString,
                        Status = "Online",
                        OpenPorts = "N/A"
                    };

                    // Debug print to verify data
                    Console.WriteLine($"Found device - IP: {ipAddress}, MAC: {macAddressString}");

                    return scanResult;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error scanning {ipAddress}: {ex.Message}");
            }

            return null;
        }

        private void cmbTypeScan_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            UpdateScanDescription();
        }

        private void btnStopScan_Click(object sender, RoutedEventArgs e)
        {
            //TODO - implement logic to stop scan
            btnStartScan.IsEnabled = true;
            btnStopScan.IsEnabled = false;
            progressGrid.Visibility = Visibility.Collapsed;
        }
    }

    public class ScanResult : INotifyPropertyChanged
    {
        private string _ipAddress;
        private string _macAddress;
        private string _status;
        private string _openPorts;

        public string IpAddress
        {
            get => _ipAddress;
            set
            {
                _ipAddress = value;
                OnPropertyChanged(nameof(IpAddress));
            }
        }

        public string MacAddress
        {
            get => _macAddress;
            set
            {
                _macAddress = value;
                OnPropertyChanged(nameof(MacAddress));
            }
        }

        public string Status
        {
            get => _status;
            set
            {
                _status = value;
                OnPropertyChanged(nameof(Status));
            }
        }

        public string OpenPorts
        {
            get => _openPorts;
            set
            {
                _openPorts = value;
                OnPropertyChanged(nameof(OpenPorts));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

还有扫描仪的前端:

<Page x:Class="NetVision.Pages.NetworkTools.NetworkScan"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:NetVision.Pages.NetworkTools"
      mc:Ignorable="d" 
      d:DesignHeight="600" d:DesignWidth="1000"
      Title="Network Scan"
      Loaded="Page_Loaded">

    <Grid Margin="20">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!-- Subnet Input -->
        <Grid Grid.Row="0" Margin="0,0,0,10">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="200"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <TextBlock Text="Subnet:" Grid.Column="0" VerticalAlignment="Center" Foreground="White" Margin="0,0,10,0"/>
            <TextBox x:Name="txtSubnet" Grid.Column="1" Margin="0,0,10,0" KeyDown="txtSubnet_KeyDown"/>
            <Button x:Name="btnAddSubnet" Grid.Column="2" Content="Add Subnet" Style="{StaticResource BaseButtonStyle}" Click="btnAddSubnet_Click"/>

            <!-- Error Message -->
            <TextBlock x:Name="txtErrorMessage" Grid.Column="3" Foreground="Red" VerticalAlignment="Center" Margin="10,0,0,0" TextWrapping="Wrap"/>
        </Grid>

        <!-- Scan Controls -->
        <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,0,0,10">
            <Button x:Name="btnStartScan" Content="Start Scan" Style="{StaticResource BaseButtonStyle}" Click="btnStartScan_ClickAsync" Margin="0,0,10,0"/>
            <Button x:Name="btnStopScan" Content="Stop Scan" Style="{StaticResource BaseButtonStyle}" Click="btnStopScan_Click" IsEnabled="False"/>

            <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="20,0,0,0">
                <TextBlock Text="Scan Type:" Foreground="White" VerticalAlignment="Center" Margin="0,0,10,0"/>
                <ComboBox x:Name="cmbTypeScan" Width="120" SelectedIndex="0" SelectionChanged="cmbTypeScan_SelectionChanged">
                    <ComboBoxItem Content="ARP Scan"/>
                    <ComboBoxItem Content="TCP/UDP Scan"/>
                    <ComboBoxItem Content="TCP Scan"/>
                    <ComboBoxItem Content="UDP Scan"/>
                    <ComboBoxItem Content="PING Scan"/>
                </ComboBox>
            </StackPanel>
        </StackPanel>


        <!-- Scan Description -->
        <TextBlock Grid.Row="3" x:Name="txtScanDescription" Foreground="White" VerticalAlignment="Top" Margin="0,0,0,10" TextWrapping="Wrap"/>

        <!-- Scan Results -->
        <Grid Grid.Row="3" Margin="0,30,0,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="200"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <!-- Subnet List -->
            <Border Grid.Column="0" Style="{StaticResource CardStyle}" Margin="0,0,10,0">
                <StackPanel>
                    <TextBlock Text="Subnets to Scan" Style="{StaticResource CardTitleStyle}"/>
                    <ListBox x:Name="lstSubnets" Background="Transparent" Foreground="White">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="*"/>
                                        <ColumnDefinition Width="Auto"/>
                                    </Grid.ColumnDefinitions>
                                    <TextBlock Text="{Binding}" VerticalAlignment="Center"/>
                                    <Button Grid.Column="1" Content="❌" 
                                            Background="Transparent" BorderThickness="0" 
                                            Foreground="Red" Padding="5,0"
                                            Click="btnDeleteSubnet_Click"/>
                                </Grid>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </StackPanel>
            </Border>



            <!-- Scan Results Table -->
            <Border Grid.Column="1" Style="{StaticResource CardStyle}" Margin="0,0,0,0">
                <StackPanel>
                    <TextBlock Text="Scan Results" Style="{StaticResource CardTitleStyle}"/>
                    <Grid x:Name="progressGrid" Visibility="Collapsed" Margin="0,0,0,10">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>
                        <ProgressBar x:Name="scanProgressBar" Height="20" Value="0"/>
                        <TextBlock x:Name="progressText" Grid.Row="1" Foreground="White" 
                      HorizontalAlignment="Center" Margin="0,5,0,0"
                      Text="Scanning: 0/0 hosts"/>
                    </Grid>
                    <DataGrid x:Name="dgScanResults" 
                  AutoGenerateColumns="False" 
                  IsReadOnly="True" 
                  Background="Transparent" 
                  BorderThickness="0"
                  Foreground="White">
                        <DataGrid.Columns>
                            <DataGridTextColumn Header="IP Address" 
                                  Binding="{Binding IpAddress}" 
                                  Width="*">
                                <DataGridTextColumn.ElementStyle>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="Foreground" Value="White"/>
                                    </Style>
                                </DataGridTextColumn.ElementStyle>
                            </DataGridTextColumn>
                            <DataGridTextColumn Header="MAC Address" 
                                  Binding="{Binding MacAddress}" 
                                  Width="*">
                                <DataGridTextColumn.ElementStyle>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="Foreground" Value="White"/>
                                    </Style>
                                </DataGridTextColumn.ElementStyle>
                            </DataGridTextColumn>
                            <DataGridTextColumn Header="Status" 
                                  Binding="{Binding Status}" 
                                  Width="*">
                                <DataGridTextColumn.ElementStyle>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="Foreground" Value="White"/>
                                    </Style>
                                </DataGridTextColumn.ElementStyle>
                            </DataGridTextColumn>
                            <DataGridTextColumn Header="Open Ports/Protocols" 
                                  Binding="{Binding OpenPorts}" 
                                  Width="*">
                                <DataGridTextColumn.ElementStyle>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="Foreground" Value="White"/>
                                    </Style>
                                </DataGridTextColumn.ElementStyle>
                            </DataGridTextColumn>
                        </DataGrid.Columns>
                    </DataGrid>
                </StackPanel>
            </Border>
        </Grid>
    </Grid>
</Page>

由于某种原因,它看起来是这样的: gui_frontend_scanner

c# windows network-programming arp
1个回答
0
投票

这是一个视觉问题,您的文本在白色背景上是白色的您的数据在那里,但您看不到它......尝试更改背景将修复它

<DataGridTextColumn.ElementStyle>
    <Style TargetType="TextBlock">
        <Setter Property="Background" Value="#333"/>
        <Setter Property="Foreground" Value="White"/>
    </Style>
</DataGridTextColumn.ElementStyle>
© www.soinside.com 2019 - 2024. All rights reserved.