节点在线、应用在线、配置在线使用令牌查询
大石头 authored at 2021-12-16 19:49:30
6.16 KiB
Stardust
using System.ComponentModel;
using System.Net;
using AgentExpansion;
using NewLife.Log;
using Xunit;

namespace Stardust.Tests;

/// <summary>局域网扫描地址解析测试</summary>
/// <remarks>
/// AgentExpansion 插件只扫描 RFC1918 局域网网段,链路本地 169.254.0.0/16 等地址必须排除,
/// 否则无线直连/蓝牙/虚拟网卡的 /16 掩码会展开成六万多个地址,导致每小时一轮的全网段探测刷爆日志。
/// 通过链接插件源码直测(AgentExpansion 为插件工程,不便于直接引用)。
/// </remarks>
public class LanScanTests
{
    [Theory]
    [InlineData("10.0.0.1", true)]
    [InlineData("10.255.255.254", true)]
    [InlineData("172.15.255.255", false)]
    [InlineData("172.16.0.1", true)]
    [InlineData("172.31.255.254", true)]
    [InlineData("172.32.0.1", false)]
    [InlineData("192.168.1.1", true)]
    [InlineData("192.169.1.1", false)]
    [DisplayName("IsLanAddress_RFC1918边界")]
    public void IsLanAddress_Rfc1918Boundary(String address, Boolean expected)
    {
        Assert.Equal(expected, LanScan.IsLanAddress(IPAddress.Parse(address)));
    }

    [Theory]
    [InlineData("169.254.0.1")]
    [InlineData("169.254.255.254")]
    [InlineData("127.0.0.1")]
    [InlineData("0.0.0.1")]
    [InlineData("100.64.0.1")]
    [InlineData("198.18.0.1")]
    [InlineData("224.0.0.1")]
    [InlineData("240.0.0.1")]
    [InlineData("255.255.255.255")]
    [InlineData("8.8.8.8")]
    [DisplayName("IsLanAddress_非局域网地址被排除")]
    public void IsLanAddress_NonLan_Excluded(String address)
    {
        Assert.False(LanScan.IsLanAddress(IPAddress.Parse(address)));
    }

    [Fact]
    [DisplayName("IsLanAddress_空值与IPv6被排除")]
    public void IsLanAddress_Null_Excluded()
    {
        Assert.False(LanScan.IsLanAddress(null));
        Assert.False(LanScan.IsLanAddress(IPAddress.IPv6Loopback));
    }

    [Fact]
    [DisplayName("ParseNetworks_空值_返回空集合")]
    public void ParseNetworks_Empty_ReturnsEmpty()
    {
        Assert.Empty(LanScan.ParseNetworks(null, Logger.Null));
        Assert.Empty(LanScan.ParseNetworks("", Logger.Null));
        Assert.Empty(LanScan.ParseNetworks("   ", Logger.Null));
    }

    [Fact]
    [DisplayName("ParseNetworks_非局域网网段被忽略")]
    public void ParseNetworks_NonLan_Ignored()
    {
        var ranges = LanScan.ParseNetworks("169.254.0.0/16,0.0.0.0/0,8.8.8.8,169.254.*.*", Logger.Null);

        Assert.Empty(ranges);
    }

    [Fact]
    [DisplayName("ParseNetworks_混合配置_只保留局域网")]
    public void ParseNetworks_Mixed_OnlyLanKept()
    {
        var ranges = LanScan.ParseNetworks("169.254.0.0/16,10.0.0.0/8,192.168.1.*", Logger.Null);

        Assert.Equal(2, ranges.Count);
        Assert.Equal(IPAddress.Parse("10.0.0.1"), ranges[0].Start);
        Assert.Equal(IPAddress.Parse("10.255.255.254"), ranges[0].End);
        Assert.Equal(IPAddress.Parse("192.168.1.1"), ranges[1].Start);
        Assert.Equal(IPAddress.Parse("192.168.1.254"), ranges[1].End);
    }

    [Fact]
    [DisplayName("ParseNetworks_尾部通配符_排除网络与广播地址")]
    public void ParseNetworks_TrailingWildcard_ExcludesNetworkAndBroadcast()
    {
        var ranges = LanScan.ParseNetworks("192.168.*.*", Logger.Null);

        var range = Assert.Single(ranges);
        Assert.Equal(IPAddress.Parse("192.168.0.1"), range.Start);
        Assert.Equal(IPAddress.Parse("192.168.255.254"), range.End);
    }

    [Fact]
    [DisplayName("ParseNetworks_非连续通配符_保持原区间")]
    public void ParseNetworks_NonContiguousWildcard_KeepsRawRange()
    {
        var ranges = LanScan.ParseNetworks("10.*.1.*", Logger.Null);

        var range = Assert.Single(ranges);
        Assert.Equal(IPAddress.Parse("10.0.1.0"), range.Start);
        Assert.Equal(IPAddress.Parse("10.255.1.255"), range.End);
    }

    [Fact]
    [DisplayName("ParseNetworks_单个地址_构成单点区间")]
    public void ParseNetworks_SingleAddress()
    {
        var ranges = LanScan.ParseNetworks("192.168.1.10", Logger.Null);

        var range = Assert.Single(ranges);
        Assert.Equal(IPAddress.Parse("192.168.1.10"), range.Start);
        Assert.Equal(IPAddress.Parse("192.168.1.10"), range.End);
    }

    [Fact]
    [DisplayName("FromCidr_排除网络地址与广播地址")]
    public void FromCidr_ExcludesNetworkAndBroadcast()
    {
        var range = NetworkRange.FromCidr(IPAddress.Parse("10.10.140.224"), 20);

        Assert.Equal(IPAddress.Parse("10.10.128.1"), range.Start);
        Assert.Equal(IPAddress.Parse("10.10.143.254"), range.End);
        Assert.Equal(4094, range.GetAddresses().Count());
    }

    [Fact]
    [DisplayName("Distinct_同网段重复_去重")]
    public void Distinct_SameRange_Deduplicated()
    {
        var ranges = LanScan.ParseNetworks("192.168.1.0/24,192.168.1.1/24,192.168.2.0/24", Logger.Null);
        Assert.Equal(3, ranges.Count);

        var distinct = LanScan.Distinct(ranges);
        Assert.Equal(2, distinct.Count);
    }

    [Fact]
    [DisplayName("GetTargets_超过上限_按上限截断")]
    public void GetTargets_OverLimit_Truncated()
    {
        var ranges = LanScan.ParseNetworks("192.168.1.0/24", Logger.Null);

        var all = LanScan.GetTargets(ranges, 0, Logger.Null).ToList();
        Assert.Equal(254, all.Count);

        var capped = LanScan.GetTargets(ranges, 5, Logger.Null).ToList();
        Assert.Equal(5, capped.Count);
        Assert.Equal(IPAddress.Parse("192.168.1.1"), capped[0]);
        Assert.Equal(IPAddress.Parse("192.168.1.5"), capped[4]);
    }

    [Fact]
    [DisplayName("GetLocalRanges_不含链路本地等非局域网网段")]
    public void GetLocalRanges_OnlyLan()
    {
        var ranges = LanScan.GetLocalRanges();

        // 本机网卡解析出的网段必须全部是局域网,绝不能包含 169.254.0.0/16
        foreach (var range in ranges)
        {
            Assert.True(LanScan.IsLanAddress(range.Start), $"网段 {range.Start} 不是局域网地址");
            Assert.True(LanScan.IsLanAddress(range.End), $"网段 {range.End} 不是局域网地址");
        }

        var huge = ranges.Where(e => e.Start.GetAddressBytes()[0] == 169).ToList();
        Assert.Empty(huge);
    }
}