无法回应的ARP请求包导致的网站缓慢问题排错

简介:

问题

访问一个网站,从本地访问很快,但是从客户端访问大概要等待3秒的样子。在服务器放上静态网页,在客户端访问则返回时间很快。

排错步骤

  • 在客户端访问问题网站,在客户端用wireshark抓包

    1. 用tcp 三次握手及客户端请求与服务器返回的ACK来判断是否存在线路或者服务器忙问题,发现不是。348-349 显示出服务器响应很快。 349-498 之间用了3.28秒,说明这是服务器应用的问题。

    无法回应的ARP请求包导致的网站缓慢问题排错

  • 让开发人员调查服务器端的应用,开发人员说之前有个小功能可以抓取客户端MAC地址,但是看到抓的包,应该不是用的客户端的代码,因为第一个web页响应就3秒多,要是客户端代码那也是后续的JS或者资源加载较慢。

  • 不管三七二十一,在服务器端也抓了下包。过滤下arp 和http的包看看,过滤后发现有三个ARP请求,但是没有对应回应。另外仔细看ARP请求的具体内容也不对,服务器用ARP请求去解析客户端的MAC地址应该是不对的,原因是服务器和客户端不在一个网段,正常的跨网段的ARP请求是同一个网段才会用的,如果跨网段那应该去解析路由器的MAC地址。所以这些ARP请求有问题。

无法回应的ARP请求包导致的网站缓慢问题排错

  • 开发人员注释掉了客户端ARP地址查询的代码。访问速度瞬间提升了。
  • 开发人员同时注意到客户端ARP地址查询的结果为00-00-00-00-00-00,和我们的服务器上的抓包结果一致,因为去请求一个跨网段IP地址的MAC,所以目标地址不会收到,因为ARP广播会在路由器端终止。

揭开真相

  • 开发人员给了我服务器端的代码C#
    ``` c#
    [DllImport("Iphlpapi.dll")]
    private static extern int SendARP(Int32 dest, Int32 host, ref Int64 mac, ref Int32 length);
    [DllImport("Ws2_32.dll")]
    private static extern Int32 inet_addr(string ip);

    public string getClientMac(string userip)
    {
        if (string.IsNullOrEmpty(userip)) return null;
        //string userip = Request.UserHostAddress;
        string strClientIP = userip.ToString().Trim();
        Int32 ldest = inet_addr(strClientIP);
        Int32 lhost = inet_addr("");
        Int64 macinfo = new Int64();
        Int32 len = 6;
        int res = SendARP(ldest, 0, ref macinfo, ref len);
        string mac_src = macinfo.ToString("X");
        //if (mac_src == "0")
        //{
        //    ip = userip;
        //}
    
        while (mac_src.Length < 12)
        {
            mac_src = mac_src.Insert(0, "0");
        }
    
        string mac_dest = "";
    
        for (int i = 0; i < 11; i++)
        {
            if (0 == (i % 2))
            {
                if (i == 10)
                {
                    mac_dest = mac_dest.Insert(0, mac_src.Substring(i, 2));
                }
                else
                {
                    mac_dest = "-" + mac_dest.Insert(0, mac_src.Substring(i, 2));
                }
            }
        }
    
        return mac_dest;
    }

* 按照代码逻辑的话,服务器应该是用了一次SendARP 调用,但是为什么会有三个ARP请求产生,而且不同的ARP请求包之间的等待时间不一。所以为了验证这个SendARP的调用的实际操作,我用powershell 写了上面一个sendARP 调用,然后用wireshark抓包。
``` powershell
Function Send-Arp { 
param( 
    [string]$DstIpAddress, 
    [string]$SrcIpAddress = 0 
) 

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

    Add-Type -MemberDefinition $signature -Name Utils -Namespace Network 

    try { 
        $DstIp = [System.Net.IPAddress]::Parse($DstIpAddress) 
        $DstIp = [System.BitConverter]::ToInt32($DstIp.GetAddressBytes(), 0) 
    } catch { 
        Write-Error "Could not convert $($DstIpAddress) to an IpAddress type.  Please verify your value is in the proper format and try again." 
        break 
    } 

    if ($SrcIpAddress -ne 0) { 
        try { 
            $SrcIp = [System.Net.IPAddress]::Parse($SrcIpAddress) 
            $SrcIp = [System.BitConverter]::ToInt32($SrcIp.GetAddressBytes(), 0) 
        } catch { 
            Write-Error "Could not convert $($SrcIpAddress) to an IpAddress type.  Please verify your value is in the proper format and try again." 
            break 
        } 
    } else { 
        $SrcIp = $SrcIpAddress 
    } 

    $New = New-Object PSObject -Property @{ 
        IpAddress = $DstIpAddress 
        PhysicalAddress = '' 
        Description = '' 
        ArpSuccess = $true 
    } | Select-Object IpAddress,PhysicalAddress,ArpSuccess,Description 

    $MacAddress = New-Object Byte[] 6 
    $MacAddressLength = [uint32]$MacAddress.Length 

    $Ret = [Network.Utils]::SendARP($DstIp, $SrcIp, $MacAddress, [ref]$MacAddressLength) 

    if ($Ret -ne 0) { 
        $New.Description =  "An error was returned from SendArp() with error code:  $($Ret)" 
        $New.ArpSuccess = $false 
    } else { 
        $MacFinal = @() 
        foreach ($b in $MacAddress) { 
            $MacFinal += $b.ToString('X2') 
        } 

        $New.PhysicalAddress = ($MacFinal -join ':') 
    } 

    Write-Output $New 
} 
  • 使用powershell 来解析一个跨网段的目标IP地址,然后紧接着ping目标主机,这样可以根据ping包的开始时间得出sendARP 的结束时间。
    powershell 命令如下:

    send-arp serverIP ;ping serverIP
  • 抓包过滤ARP以及ICMP来验证,SendARP函数会发送三个ARP包,可能也会等待超时,因为没有ARP包回应,这个测试的时间大概也在3.1秒左右,符合问题现象。
    无法回应的ARP请求包导致的网站缓慢问题排错

最后总结:

  1. 在服务器上本机访问非常快,是因为服务器使用ARP请求查本机,应该会很快有回应。如果其他客户端和服务器在同一个网段,估计也不会慢。

  2. 客户端慢是因为服务器在返回给客户端http信息时,先用ARP请求跨网段的客户端IP,但是不会有ARP回应,因为路由的原因,客户端看不到服务器的ARP请求,而SendARP函数的超时时间大概为3.1秒,所以跨网段的客户端收到服务器的一个HTTP响应在3.28秒左右。同样单纯在客户端抓包只能分析出服务器应用有问题,但是说不出具体的问题。

  3. 静态网页快是因为,静态网页不执行服务器端代码,所以不会执行ARP查询。

  4. 另外开发人员也应该熟悉常见的网络协议,像这次的代码就会仅仅在特定场景下工作,如果网站是面向互联网的话,那这个代码将不会起到作用,反而影响性能
本文转自 yoke88 51CTO博客,原文链接:http://blog.51cto.com/yoke88/2053667

相关文章
|
6月前
|
网络协议
[DPDK] 发arp包
[DPDK] 发arp包
|
6月前
|
缓存 网络协议
Wireshark中的ARP协议包分析
Wireshark可以跟踪网络协议的通讯过程,本节通过ARP协议,在了解Wireshark使用的基础上,重温ARP协议的通讯过程。 ARP(Address Resolution Protocol)地址解析协议,是根据IP地址获取物理地址的一个TCP/IP协议。 主机发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。 在Wireshark界面,我们可以看到19、20号数据包,就是一对标准的ARP请求和响应包。
|
网络协议 数据安全/隐私保护 Windows
arp获取https网站的用户名密码 (1)
arp获取https网站的用户名密码 (1)
|
网络协议 安全
kali:加速WEP黑客攻击,ARP请求重播攻击
版权声明:转载请注明出处:http://blog.csdn.net/dajitui2024 https://blog.csdn.net/dajitui2024/article/details/79396280 ...
1039 0
|
1天前
|
网络协议 安全 NoSQL
网络空间安全之一个WH的超前沿全栈技术深入学习之路(8-2):scapy 定制 ARP 协议 、使用 nmap 进行僵尸扫描-实战演练、就怕你学成黑客啦!
scapy 定制 ARP 协议 、使用 nmap 进行僵尸扫描-实战演练等具体操作详解步骤;精典图示举例说明、注意点及常见报错问题所对应的解决方法IKUN和I原们你这要是学不会我直接退出江湖;好吧!!!
网络空间安全之一个WH的超前沿全栈技术深入学习之路(8-2):scapy 定制 ARP 协议 、使用 nmap 进行僵尸扫描-实战演练、就怕你学成黑客啦!
|
26天前
|
缓存 网络协议 Linux
Python渗透测试之ARP毒化和协议应用
Python渗透测试之ARP毒化和协议应用
25 0
|
3月前
|
网络协议
用户态协议栈04-定时arp-table的实现
用户态协议栈04-定时arp-table的实现
|
3月前
|
缓存 网络协议
用户态协议栈02-arp reply实现
用户态协议栈02-arp reply实现