locked
how to add additional header field in OUTBOUND_TRANSPORT_LAYER RRS feed

  • Question

  • Hi,

    I am Aravind.

    I need to add additional header(s) to the packet in OUTBOUND_TRANSPORT_LAYER. Kindly let me know how can i do this.

    Also clarify whether "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)." this is true in my case also.

    If not let me know about checksum calculation.

    refrence: http://social.msdn.microsoft.com/Forums/en/wfp/thread/a3cfd784-ca61-49e5-835a-f934a5348787

    please help
    Wednesday, August 5, 2009 1:20 PM

Answers

  • So you are adding a TCP option after the TCP header?

    Try the following procedure:


    1. For each packet (i.e. NET_BUFFER) in the original NET_BUFFER_LIST call NdisAdvanceNetBufferDataStart with the inMetaValues->transportHeaderSize amount.

    2. Clone the NET_BUFFER_LIST using FwpsAllocateCloneNetBufferList0. The clone packets will all begin with transport data (e.g. TCP payload).

    3. For each packet (i.e. NET_BUFFER) in the original NET_BUFFER_LIST call NdisRetreatNetBufferDataStart with the inMetaValues->transportHeaderSize. (i.e. restore the original NBL to its original state)

    4. For each packet (i.e. NET_BUFFER) in the cloned NET_BUFFER_LIST, call NdisRetreatNetBufferDataStart with a delta that's big enough to hold the TCP header and the options that you are adding; Use NdisGetDataBuffer to get the pointer to the newly created buffer and copy over the original TCP header and the new options.

    5. Call FwpsInjectTransportSendAsync0 with sendArgs.

    6. BLOCK & obsorb the original NBL.

    For TCP payload modification, please refer to this page http://msdn.microsoft.com/en-us/library/aa938501.aspx. The FWPS_STREAM_FLAG_SEND stream flag indicates outgoing data segments.

    Biao.W.
    • Marked as answer by arvind_trinity Thursday, January 7, 2010 11:04 AM
    Friday, September 4, 2009 7:01 AM
  • Hi Biao,

    Thanks a lot for all the help.

    There was a mistake in my tcp header structure, after i fixed it, it worked.
    I am successful in sending packets after adding additional data both to tcp header and to tcp payload. The former needs data offset to be adjusted and the later needs seq and ack numbers to be adjusted.

    Thanks
    Aravind
    Monday, September 14, 2009 7:11 AM
  • In the original classifyFn, set the classifyOut->actionType = FWP_ACTION_BLOCK and classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB.

    Hope this helps,


    Dusty Harper [MSFT]
    Microsoft Corporation
    ------------------------------------------------------------
    This posting is provided "AS IS", with NO warranties and confers NO rights
    ------------------------------------------------------------

    Wednesday, February 29, 2012 11:19 PM
    Moderator

All replies

  • Try the following procedure:

    1. Clone the NET_BUFFER_LIST using FwpsAllocateCloneNetBufferList0. The clone packets all begin with transport header.

    2. For each packet (i.e. NET_BUFFER) in the cloned NET_BUFFER_LIST:

          a) Call NdisRetreatNetBufferDataStart with a delta that's big enough to hold the IP header and the extensions that you are adding
          b) Call NdisAdvanceNetBufferDataStart with the same amount.

       Now the clone packets still begin with transport header, but you just created a contiguous space in front of it to hold the IP header and extensions.

    3. Call FwpsConstructIpHeaderForTransportPacket0 to build the IP headers (headerIncludeHeaderSize param should be 0)

    4. For each packet (i.e. NET_BUFFER) in the cloned NET_BUFFER_LIST:

           a) NdisGetDataBuffer to get pointer to the beginning of IP header
           b) move the IP address forward to make room your the exensions
           c) copy the extensions to fill the "hole"
           d) re-calculate IP checksum

    5. Call FwpsInjectTransportSendAsync0 without sendArgs.


    Thanks,
    Biao.W.
    Friday, August 7, 2009 6:53 AM
  • Thanks Biao.W

    Is there any other easy way where i can add my own header without having to recalculate checksum? I am using Win7.

    Also plz let me know how can i recalculate tcp checksum in the above said procedure(4d) and do i need to use DPC for this type of injection?.

    Aravind
    Tuesday, August 18, 2009 7:08 AM
  • You shouldn't need to update TCP checksum; just patching the IP header checksum should do.

    Yes for TCP traffic you can't inject from within classifyFn -- you will need to queue DPC or call it from a worker thread.

    Thanks,
    Biao.W.
    • Marked as answer by arvind_trinity Wednesday, August 19, 2009 7:38 AM
    • Unmarked as answer by arvind_trinity Thursday, August 27, 2009 5:45 AM
    Wednesday, August 19, 2009 7:33 AM
  • Thanks a lot Mr.Biao W.

    I am trying this out. Will get back to you if i ran into touble.
    Wednesday, August 19, 2009 7:38 AM
  • Hi,

    What if i need to add it after tcp header...

    Will the above said method hold good for this too. But in this case
    - i ll have to move both tcp header and ip header and then insert my header.
    - then recalculate the tcp checksum.
    - then reinject the packet without send args.

    or

    - clone the packet.
    - call NdisRetreatNetBufferDataStart with space equal to the data i need to allocate space.
    - now i move tcp header to the beginging of the buffer.
    - then fill the data required after the tcp header.
    - then call FwpsInjectTransportSendAsync0 with sendArgs so that it ll recalculate my checksum.

    Which one of the above said procedure will work?
    Plz help.

    Aravind

    Thursday, August 27, 2009 8:18 AM
  • Hi,

    Any thoughts on this i am starting to work on this...

    Aravind
    Monday, August 31, 2009 4:24 AM
  • Hi - Method 2 should work.
    Anu
    Monday, August 31, 2009 6:49 PM
  • Hi,

    I am having trouble allocating extra space between tcp header and tcp data in outbound transport layer.
    Please help.

    This is what i did:

    1) Cloned the incoming NBL

    status = FwpsAllocateCloneNetBufferList0(
                   packet->netBufferList,
                   NULL,
                   NULL,
                   0,
                   &clonedNetBufferList
                   );
       if (!NT_SUCCESS(status))
       {
        FreePendedPacket(packet);
          goto Exit;
       }

    2) Then for each NB in NBL retreat by the amount i needed then try to use NdisGetDataBuffer to get the required data

    for (netBuffer = NET_BUFFER_LIST_FIRST_NB(clonedNetBufferList);
               netBuffer != NULL;
               netBuffer = NET_BUFFER_NEXT_NB(netBuffer))
        {
         //logic for adding header information
              NdisRetreatNetBufferDataStart(
         netBuffer,
         sizeof(CUSTOM_HEADER)
         0,
         NULL
         );

         if(!NT_SUCCESS(status))
         {
          DbgPrint("RETREAT opertion FAILED!!!\n");
         }

         tcp_header = (TCP_HEADER *) NdisGetDataBuffer(
                                   netBuffer,
              sizeof(TCP_HEADER) + sizeof(MOBICIP_HEADER),
              NULL,
              1,
              0);

         if(!temp)
         {
          DbgPrint("error in getDataBuffer\n");
          goto Exit;
         }

    But when i did that i always get temp to be NULL.
    I read about this in MSDN which says that this might happen when the required size of data from the packet is not in contiguous memory location.

    So all i need is to add the required space after the tcp header and before the tcp data. Please help.

    NOTE: i cannot switch to anyother layer as i ve other manupulation in this layer.

    Aravind

    Tuesday, September 1, 2009 5:31 PM
  • pretty sure you need to retreat "sizeof(TCP_HEADER) + sizeof(MOBICIP_HEADER)".

    thanks,
    Biao.W.

    Wednesday, September 2, 2009 4:45 AM
  • Hi Baio.W

    Dont i already have TCP header in outbound tcp layer as the packet begins with tcp header?
    Retreating by "sizeof(TCP_HEADER) + sizeof(MOBICIP_HEADER)" wont be a leak?
    that is i am allocating space for tcp header which is already there...

    Please help as i couldn understand.

    Aravind
    Wednesday, September 2, 2009 5:12 AM
  • My bad -- I meant to say you need to retreat "<ip header size> +  sizeof(MOBICIP_HEADER)". Now you won't know the precise ip header size as in OUTBOUND_TRANSPORT the IP header is not yet build, so you need to over-estimate a little more than the fixed IP header size.

    you would ask for the same amount when calling NdisGetDataBuffer.

    you current code fails becasue in NdisGetDataBuffer you ask more than what's contiguously available.

    thanks,
    biao.W.

    Thursday, September 3, 2009 12:16 AM
  • Hi Biao.W,

    Thanks a lot for the help. But i need to allocate memory after tcp header and before tcp data.
    Can you please walk across the steps needed it would be of really great help.

    Also i read that to change tcp data the best place to do is STREAM layer but i need to change it in outbound TCP.
    Please let me know is there a standard way of doing this or i need to tweak something.

    Thanks a lot
    Aravind

    Thursday, September 3, 2009 12:06 PM
  • So you are adding a TCP option after the TCP header?

    Try the following procedure:


    1. For each packet (i.e. NET_BUFFER) in the original NET_BUFFER_LIST call NdisAdvanceNetBufferDataStart with the inMetaValues->transportHeaderSize amount.

    2. Clone the NET_BUFFER_LIST using FwpsAllocateCloneNetBufferList0. The clone packets will all begin with transport data (e.g. TCP payload).

    3. For each packet (i.e. NET_BUFFER) in the original NET_BUFFER_LIST call NdisRetreatNetBufferDataStart with the inMetaValues->transportHeaderSize. (i.e. restore the original NBL to its original state)

    4. For each packet (i.e. NET_BUFFER) in the cloned NET_BUFFER_LIST, call NdisRetreatNetBufferDataStart with a delta that's big enough to hold the TCP header and the options that you are adding; Use NdisGetDataBuffer to get the pointer to the newly created buffer and copy over the original TCP header and the new options.

    5. Call FwpsInjectTransportSendAsync0 with sendArgs.

    6. BLOCK & obsorb the original NBL.

    For TCP payload modification, please refer to this page http://msdn.microsoft.com/en-us/library/aa938501.aspx. The FWPS_STREAM_FLAG_SEND stream flag indicates outgoing data segments.

    Biao.W.
    • Marked as answer by arvind_trinity Thursday, January 7, 2010 11:04 AM
    Friday, September 4, 2009 7:01 AM
  • Hi Biao.W

    Thanks a lot for the great information i am struggling in this for almost a week now.

    I need one additional information:
    Will i need to modify the seq number of tcp header?

    Thanks once again for the great help.

    Regards
    Aravind
    Friday, September 4, 2009 7:09 AM
  • No but you need to modify the Data Offset field to include the new options...

    Friday, September 4, 2009 7:31 AM
  • Hi Biao.W,

    But souldn't NdisAdvanceNetBufferDataStart and NdisRetreatNetBufferDataStart change the data-offset?

    Aravind

    Tuesday, September 8, 2009 6:00 AM
  • The ndis functions adjust the offsets of the NET_BUFFERs (such that it points to IP header, TCP header, TCP payload, etc).

    It does not affect the Data Offset field of the TCP header -- for that you will need to position the NET_BUFFER to the beginning of TCP header, then use NdisGetDataBuffer to get to the pointer to the TCP header, maps that to the TCP_HDR data structure, and finally modifies the Data Offset field.

    Thanks,
    Biao.W.
    Wednesday, September 9, 2009 4:14 AM
  • Hi Biao,

    Thanks a lot. But i need to add additional data to tcp payload and in trasnport layer.

    Anyways when i checked data offset field of original tcp header is always "0".

    typedef struct _TCP_HEADER
    {
    UINT16 srcPort;
    UINT16 destPort;
    UINT32 seq;
    UINT32 ackNumber;
    UINT16 doff:4;
    UINT16 unused:6;
    UINT16 urg:1;
    UINT16 ack:1;
    UINT16 psh:1;
    UINT16 rst:1;
    UINT16 syn:1;
    UINT16 fin:1;
    UINT16 window;
    UINT16 checkSum;
    UINT16 urgPtr;
    }TCP_HEADER;

    netBuffer = NET_BUFFER_LIST_FIRST_NB(packet->netBufferList);
    tcp_header1 = NdisGetDataBuffer(
                             netBuffer,
        packet->transportHeaderSize,
        NULL,
        1,
        0);

    DbgPrint("old TCP Data Offset = %hu\n",tcp_header1->doff);

    Always prints "0". Am i doing something wrong or this is the correct value.
    As far as i know data offset of tcp header cannot be less than 5.

    Also thanks a lot as this method worked one way. i was able to read the packets from my application in the remote server but the reply packet that i sent is rejected by transport layer (i could find them in transport discard layer). But the reject reason is not any one of the given reasons. So plz help to find the actual reject reason. Now i am totally blank of what exactly is happening...

    All i need to do is add extra bytes to tcp payload. Plz clarify whether i need to change checksum or seq number. I guess i dont have to change data offset as i am not changing the tcp header size.

    Please help me to add data to tcp payload from transport outbound layer.

    Aravind

    Wednesday, September 9, 2009 6:02 AM
  • TCP Data Offset shouldn't be 0 -- it should be the number of 32 bit words in the TCP Header including the options & padding that you added. Without that adjusted properly I think the remote end will see the new options being part of data and it's not surprising that things break. I am not sure you had packed the struct correctly -- but anyway the first 4 bits of the 12th byte (0-based) should be the TCP Data Offset.

    Adding extra bytes to payload at TRANSPORT would be difficult -- you would need to adjust the sequence/ack# as modifications are done w/o TCP's knowledge. STREAM layer is a much more friendly layer for that since sequence/ack# will be adjusted automatically.

    Thanks,
    Biao.W.

    Thursday, September 10, 2009 2:25 AM
  • Hi Biao,

    Sorry for bothering you again, I have one more doubt. The packet that is reinjected from TCP layer again passes through tcp layer right?
    So if the checksum is recalculated why not seq/ack numbers?

    Is there anything i can do to make tcp calculate seq/ack number? that is like make this a new packet so all the calculations are done again.

    Anyways if i am suppose to do the calculation how can i get to know the total size of tcp payload? I have already started to work on the seq/ack numbers, any inputs would be of great help.

    Thanks a lot for your help.

    Regards
    Aravind
    Thursday, September 10, 2009 2:52 AM
  • TL send-injected packets don't re-enter the TCP state-machine. It should be quite easy to add content from the STREAM layer and the TCP state machine will take care of seq# etc.

    Why don't you take a netmon sniff of the modified packet to see if TCP Data Offset is off (i.e. whether it covers the options that you added).

    Thanks,
    Biao.W. 
    Thursday, September 10, 2009 3:06 AM
  • Hi Biao,

    Thanks a lot for all the help.

    There was a mistake in my tcp header structure, after i fixed it, it worked.
    I am successful in sending packets after adding additional data both to tcp header and to tcp payload. The former needs data offset to be adjusted and the later needs seq and ack numbers to be adjusted.

    Thanks
    Aravind
    Monday, September 14, 2009 7:11 AM
  • Hi,

    How do you perform step 6, "BLOCK & absorb the original NBL"?

    Thanks.

    Wednesday, February 29, 2012 10:22 PM
  • In the original classifyFn, set the classifyOut->actionType = FWP_ACTION_BLOCK and classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB.

    Hope this helps,


    Dusty Harper [MSFT]
    Microsoft Corporation
    ------------------------------------------------------------
    This posting is provided "AS IS", with NO warranties and confers NO rights
    ------------------------------------------------------------

    Wednesday, February 29, 2012 11:19 PM
    Moderator
  • Thank you. I will give it a try.
    Thursday, March 1, 2012 2:08 PM