locked
Checksum Error at Outbound Transport Layer RRS feed

  • Question

  •  

    Hi all.

     

    I want to modify the destination address in a packet.

    I made a callout driver based on "ddproxy" which is a sample in WDK.

    I added callouts and filters at INBOUND_TRANSPORT and OUTBOUND_TRANSPORT.

     

    I confirmed a packet(SYN) is sent to new destination with incorrect checksum using Wireshark.

    Anyway, the new destination receives the packet(SYN) and sends a packet(SYN, ACK) to the callout driver.

    (I also confirmed the fact using Wireshark)

    But ProxyCloneModifyReinjectInbound() is never called although the packet(SYN, ACK) was captured by WireShark.

    Inaddition, the callout driver doesn't send a packet(ACK) to the new destination.

     

    Could you tell me why those problems occured?

    Are they related to incorrect checksum?

    Why does my code result in incorrect checksum?

    I heard FwpsInjectTransportSendAsync0() calculates checksum.

     

    This is a part of my code.

     

    ==========================================================================

    NTSTATUS ProxyCloneModifyReinjectOutbound(IN PROXY_PENDED_PACKET* packet)
    {
        NTSTATUS status = STATUS_SUCCESS;
       
        UINT32 proxyIP = RtlUlongByteSwap(Proxy_configNewDestAddrV4); // host order -> network order

        NET_BUFFER_LIST* clonedNetBufferList = NULL;
        TCP_HEADER* tcpHeader;
        FWPS_TRANSPORT_SEND_PARAMS0 sendArgs = {0};
       
        KdPrintEx((DPFLTR_IHVDRIVER_ID, 0x1, "ProxyCloneModifyReinjectOutbound() was called"));

        status = FwpsAllocateCloneNetBufferList0(
                                                packet->netBufferList,
                                                NULL,
                                                NULL,
                                                0,
                                                &clonedNetBufferList);
        if (!NT_SUCCESS(status)) {
            goto Exit;
        }
       
        ////////////////////////////////////////////////////////////////////////////
        // Check to see if port modification is required.
        if (packet->protocol == IPPROTO_TCP && packet->targetPort != 0) {
            NET_BUFFER* netBuffer;

            for (netBuffer = NET_BUFFER_LIST_FIRST_NB(clonedNetBufferList); netBuffer != NULL; netBuffer = NET_BUFFER_NEXT_NB(netBuffer)) {
                tcpHeader = NdisGetDataBuffer(
                                            netBuffer,
                                            sizeof(TCP_HEADER),
                                            NULL,
                                            1,
                                            0);
                ASSERT(tcpHeader != NULL);
            
                tcpHeader->destPort = RtlUshortByteSwap(Proxy_configNewDestPort);
                tcpHeader->checksum = 0;
            }
        }
     
     ////////////////////////////////////////////////////////////////////////////
     sendArgs.remoteAddress = ExAllocatePoolWithTag(NonPagedPool, 4, PROXY_REMOTE_ADDRESS_TAG);
     RtlCopyMemory(sendArgs.remoteAddress, &proxyIP, 4); // network-byte order
     sendArgs.remoteScopeId = packet->remoteScopeId;
     sendArgs.controlData = packet->controlData;
     sendArgs.controlDataLength = packet->controlDataLength;

     // Send-inject the modified net buffer list to the new destination address.

     status = FwpsInjectTransportSendAsync0(
                                            Proxy_gInjectionHandle,
                                            NULL,
                                            packet->endpointHandle,
                                            0,
                                            &sendArgs,
                                            packet->addressFamily,
                                            packet->compartmentId,
                                            clonedNetBufferList,
                                            ProxyInjectComplete, // completion function
                                            packet);
        if (!NT_SUCCESS(status)) {
            goto Exit;
        }

        clonedNetBufferList = NULL; // ownership transferred to the completion function.

    Exit:

        if (clonedNetBufferList != NULL) {
            FwpsFreeCloneNetBufferList0(clonedNetBufferList, 0);
        }

        return status;
    }

    ==========================================================================

    Tuesday, April 29, 2008 9:54 AM

Answers

  • Oops I think I stand corrected.

     

    I think TCP stacks discarded the SYN-ACK since it couldn't find a matching TCB (TCB Control Block) to deliver the response to (becasue the remote port's different from what's in TCP's table).

     

    Such discarded packets will be indicated to INBOUND_TRANSPORT_DISCARD layers. You will need to catch the SYN-ACK there, modify the remote port back and receive- ineject the packet.

     

    Please review this thread for the exact steps http://forums.microsoft.com/Forums/ShowPost.aspx?PostID=3142699&SiteID=1

     

    Biao.W.

     

    Thursday, May 1, 2008 3:53 AM

All replies

  • Unlike UDP, a TCP checksum of 0 is invalid -- and you will need to recalculate the TCP checksum after modifying the port. You either update a pseudo-checksum or a full checksum depending on whether the NIC support checksum offload or not.

     

    Please refer to the checksum adjustmnet topic here http://msdn.microsoft.com/en-us/library/aa938504.aspx

     

    Hope this helps,

    Biao.W.

    Thursday, May 1, 2008 1:58 AM
  • Thanks Biao.W.

     

    I complete the code according to your answer.

     

    NDIS_TCP_IP_CHECKSUM_PACKET_INFO ChecksumInfo;
    ChecksumInfo.Value=(ULONG)(ULONG_PTR)NET_BUFFER_LIST_INF(clonedNetBufferList,TcpIpChecksumNetBufferListInfo);

     

    the ChecksumInfo.Value is zero.

     

    And I saw you said like this...(http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1769356&SiteID=1)
    FwpsInjectTransportSendAsync0 calculates the transport checksums for you if you supply the sendArgs argument and the cloned NBL begins with transport header (e..g TCP header).
    So in your csase leave the checksum bytes as 0s before you invoke this function and WFP will fill out the correct checksum.

    (I think the above is on the contrary to your answer)

     

    In addition, I knew Ethereal(or wireshark) tends to say TCP checksum is incorrect even if the checksum is correct.

     

    Anyway, I want to know why my callout driver doesn't send [ACK] to new destination after receiving [SYN, ACK] from the new destination.

    Rather than sending [ACK] to the new destination, my callout drvier tried to send packet [SYN] to original destination after receiving two [SYN, ACK]s from the new destination.

     

    Do you know why this happened?

    Thursday, May 1, 2008 3:35 AM
  • Oops I think I stand corrected.

     

    I think TCP stacks discarded the SYN-ACK since it couldn't find a matching TCB (TCB Control Block) to deliver the response to (becasue the remote port's different from what's in TCP's table).

     

    Such discarded packets will be indicated to INBOUND_TRANSPORT_DISCARD layers. You will need to catch the SYN-ACK there, modify the remote port back and receive- ineject the packet.

     

    Please review this thread for the exact steps http://forums.microsoft.com/Forums/ShowPost.aspx?PostID=3142699&SiteID=1

     

    Biao.W.

     

    Thursday, May 1, 2008 3:53 AM
  • Thanks Biao.W.

     

    It doesn't seem easy. But I'll try

     

    I think the information you gave me will be helpful to solve the problem.

     

    Thursday, May 1, 2008 4:56 AM
  • I'm tring to catch a discard packet at INBOUND_TRANSPORT_DISCARD layer.

    I did it but, can't find a field for [FWPS_METADATA_FIELD_COMPARTMENT_ID] in a classify function at INBOUND_TRANSPORT_DISCARD layer.

     

    I confirmed that like this

     

    Code Snippet

    ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_COMPARTMENT_ID));

     

     

     

    To reinject the packet, I think the value of the field is needed.

    How can I get that value?

     

    I have one more question.

    How can I check the reason why the packet was discarded?

    Could you show some sample code?

    Thursday, May 1, 2008 6:32 AM
  • Use UNSPECIFIED_COMPARTMENT_ID (0) should be fine.

     

    You can find discard reason from inMetaValues->discardMetaData.discardReason. It is of type IP_DISCARD_REASON, defined fwpsk.h header file.

     

    Biao.W.

    Thursday, May 1, 2008 7:24 AM