使用 EtherType 0x88A4 (EtherCat) 时,WriteFile 函数 (NDIS) 中出现错误 87

Posted

技术标签:

【中文标题】使用 EtherType 0x88A4 (EtherCat) 时,WriteFile 函数 (NDIS) 中出现错误 87【英文标题】:Error 87 in WriteFile function (NDIS) when using EtherType 0x88A4 (EtherCat) 【发布时间】:2021-08-19 10:45:48 【问题描述】:

我正在尝试使用 C 中 NDIS 驱动程序的 prottest.c example 代码通过第 2 层发送原始以太网帧。 该示例没有问题,但是当我修改以太类型时(0x88A4 EtherCat) 并使用必要的结构和信息调整框架,Writefile 函数总是返回错误 87(不正确的参数)。

如果没有 TCP/IP 堆栈,是否无法在第 2 层、Raw 中使用此函数编写,会出现什么问题?

感谢您的帮助。 最好的问候。

VOID
DoWriteProc(
    HANDLE  Handle
)

    PUCHAR      pWriteBuf = NULL;
    PUCHAR      pData;
    INT         SendCount;
    PETH_HEADER pEthHeader;
    DWORD       BytesWritten;
    BOOLEAN     bSuccess;

    DEBUGP(("DoWriteProc\n"));
    SendCount = 0;

    do
    
        pWriteBuf = malloc(PacketLength);

        if (pWriteBuf == NULL)
        
            DEBUGP(("DoWriteProc: Failed to malloc %d bytes\n", PacketLength));
            break;
        
        pEthHeader = (PETH_HEADER)pWriteBuf;
        pEthHeader->EthType = EthType;

        if (bUseFakeAddress)
        
            memcpy(pEthHeader->SrcAddr, FakeSrcMacAddr, MAC_ADDR_LEN);
        
        else
        
            memcpy(pEthHeader->SrcAddr, SrcMacAddr, MAC_ADDR_LEN);
        

        memcpy(pEthHeader->DstAddr, DstMacAddr, MAC_ADDR_LEN);

        pData = (PUCHAR)(pEthHeader + 1);

        *pData++ = (UCHAR)0x8C; //Lenght
        *pData++ = (UCHAR)0x45; //Res & Type

        *pData++ = (UCHAR)0xD0; //Publisher
        *pData++ = (UCHAR)0x50;
        *pData++ = (UCHAR)0x99;
        *pData++ = (UCHAR)0x45;
        *pData++ = (UCHAR)0x34;
        *pData++ = (UCHAR)0x9D;

        *pData++ = (UCHAR)0x01; //Count
        *pData++ = (UCHAR)0x00;

        *pData++ = (UCHAR)0x00; //Cycle
        *pData++ = (UCHAR)0x00;

        *pData++ = (UCHAR)0x00; //Res

        *pData++ = (UCHAR)0x28; //EAP_SM

        *pData++ = (UCHAR)0x04; //PD ID
        *pData++ = (UCHAR)0x00;

        *pData++ = (UCHAR)0x00; //Version
        *pData++ = (UCHAR)0x00;

        *pData++ = (UCHAR)0x78; //Lenght
        *pData++ = (UCHAR)0x05;

        *pData++ = (UCHAR)0x00; //Quality
        *pData++ = (UCHAR)0x00;

        unsigned char j = 0;
        for (int k = 0; k < 1400; k++) //Data
        
            *pData++ = (UCHAR)j;

            j++;
            if (j > 0xFF)
            
                j = 0;
            
        
        
        SendCount = 0;

        while (TRUE)
        

            bSuccess = (BOOLEAN)WriteFile(
                Handle,
                pWriteBuf,
                PacketLength,
                &BytesWritten,
                NULL);
            DWORD err = GetLastError();
            printf("ERROR: %i", err);
            if (!bSuccess)
            
                PRINTF(("DoWriteProc: WriteFile failed on Handle %p\n", Handle));
                break;
            
            SendCount++;

            DEBUGP(("DoWriteProc: sent %d bytes\n", BytesWritten));

            if ((NumberOfPackets != -1) && (SendCount == NumberOfPackets))
            
                break;
            
        

     while (FALSE);

    if (pWriteBuf)
    
        free(pWriteBuf);
    

    PRINTF(("DoWriteProc: finished sending %d packets of %d bytes each\n",
        SendCount, PacketLength));


HANDLE
OpenHandle(_In_ PSTR pDeviceName)
    DWORD   DesiredAccess;
    DWORD   ShareMode;
    LPSECURITY_ATTRIBUTES   lpSecurityAttributes = NULL;

    DWORD   CreationDistribution;
    DWORD   FlagsAndAttributes;
    HANDLE  Handle;
    DWORD   BytesReturned;

    DesiredAccess = GENERIC_READ | GENERIC_WRITE;
    ShareMode = 0;
    CreationDistribution = OPEN_EXISTING;
    FlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;

    Handle = CreateFileA(
        pDeviceName,
        DesiredAccess,
        ShareMode,
        lpSecurityAttributes,
        CreationDistribution,
        FlagsAndAttributes,
        NULL
    );
    if (Handle == INVALID_HANDLE_VALUE)
    
        DEBUGP(("Creating file failed, error %x\n", GetLastError()));
        return Handle;
    
    //
    //  Wait for the driver to finish binding.
    //
    if (!DeviceIoControl(
        Handle,
        IOCTL_NDISPROT_BIND_WAIT,
        NULL,
        0,
        NULL,
        0,
        &BytesReturned,
        NULL))
    
        DEBUGP(("IOCTL_NDISIO_BIND_WAIT failed, error %x\n", GetLastError()));
        CloseHandle(Handle);
        Handle = INVALID_HANDLE_VALUE;
    

    return (Handle);

【问题讨论】:

【参考方案1】:

为了安全,the driver refuses to send these types of packets by default。

当然,既然你有驱动程序的源代码,你可以随意修改这个限制——它是你的驱动程序。您可以添加一行以明确允许 0x88A4 EtherType,或删除整个 if 语句以允许 all EtherType。如果要发送“可疑”网络帧,您可以要求用户模式进程以管理员身份运行。

关于安全角度的更多细节。如果您允许不受信任的用户/程序将任意数据放置到网络上,则可能会危及或削弱网络安全性。这就是示例驱动程序(以及一般的 Windows)不允许任意程序将任意数据放到网络上的原因。

例如,可以不受限制地访问以太网层的恶意程序可以发布恶意 DHCP 服务器,将客户端指向恶意 DNS 服务器,对您的交换机进行 ARP 中毒攻击,DoS 交换机(例如,使用 802.3 x PAUSE 帧,或带有破坏 QoS 策略的 LLDPDU),或规避您可能拥有的任何防火墙策略。

这些潜在的攻击不一定会破坏交易:考虑到这大致相当于允许某人将任意非托管设备插入您网络上的以太网插孔。如果您的网络已经有措施来防御恶意以太网端点,那么从示例驱动程序中删除限制不会让事情变得更糟。或者,如果您对将运行您的驱动程序的 PC 上的所有用户和代码有一定程度的信任,那么修改驱动程序将无关紧要。或者,如果您的威胁模型已经假设网络是敌对且不可靠的,那么删除这些限制只会有助于满足您的威胁模型的期望。 ;)

【讨论】:

非常感谢@Jeffrey Tippet 的回答。删除块后,帧发送现在是正确的。但是,我会考虑您在安全级别上向我指出的指示。非常感谢您的帮助。最好的问候。 再次感谢您的回复。我借此机会直接询问您,因为我没有找到解决方案,因为我在 WriteFile 函数或 NDIS 驱动程序(我不清楚)方面遇到了相关问题,其中帧被重复发送。我在this post 中有描述。如果您能看一下并告诉我可能的解决方案,我将不胜感激。谢谢。

以上是关于使用 EtherType 0x88A4 (EtherCat) 时,WriteFile 函数 (NDIS) 中出现错误 87的主要内容,如果未能解决你的问题,请参考以下文章

在以太网帧中类型/长度字段的作用和用法。

CF1257EThe Contest线段树

CF438EThe Child and Binary Tree(生成函数+多项式开根)

CF438EThe Child and Binary Tree(生成函数+多项式开根)

RYU 中如钩构建TCP数据包,设置ACK等标志

Mac下RabbitMQ安装