locked
how to modify IP in INBOUND_IP layer RRS feed

  • Question

  • Hi,

    I am trying to de-proxy ip packets that were proxied earlier.
    In the inbound ip layer i am suppose to change the port and ip information:

    tcp_header = (TCP_HEADER *) NdisGetDataBuffer(
         clonedNetBuffer,
         sizeof(TCP_HEADER),
         NULL,
         sizeof(UINT16),
         0);

       //remodify the src port
       tcp_header->srcPort = RtlUshortByteSwap(80);

       NdisRetreatNetBufferDataStart(
          clonedNetBuffer,
          packet->ipHeaderSize,
          0,
          NULL
          );

       ip_header = (IP_HEADER *) NdisGetDataBuffer(
         clonedNetBuffer,
         sizeof(IP_HEADER),
         NULL,
         sizeof(UINT16),
         0);

       addr = (UCHAR *) &(ip_header->srcAddr);

       //remodify the src addr to original addr
       addr[0] = 202;
       addr[1] = 152;
       addr[2] = 52;
       addr[3] = 81;

    //reinject the ip packet

    status = FwpsInjectNetworkReceiveAsync0(
                   gInjectionHandle,
                   NULL,
                   0,
                   //packet->addressFamily,
                   packet->compartmentId,
                   FWPS_FIELD_INBOUND_IPPACKET_V4_INTERFACE_INDEX,
                   FWPS_FIELD_INBOUND_IPPACKET_V4_SUB_INTERFACE_INDEX,
                   clonedNetBufferList,
                   MobicipInjectComplete,
                   packet
                   );

       if (!NT_SUCCESS(status))
       {
          goto Exit;
       }

       clonedNetBufferList = NULL;

    is this the correct way to do as this is not working.
    pls help.

    Aravind

    Friday, August 21, 2009 12:00 PM

Answers

  • Hi,

    Sorry again my mistake. The error is

    status = FwpsInjectNetworkReceiveAsync0(
                   gInjectionHandleIP,
                   NULL,
                   0,
                   packet->compartmentId,
                   FWPS_FIELD_INBOUND_IPPACKET_V4_INTERFACE_INDEX,
                   FWPS_FIELD_INBOUND_IPPACKET_V4_SUB_INTERFACE_INDEX,
                   clonedNetBufferList,
                   MobicipInjectComplete,
                   packet
                   );
    in this highlighted part. When i replaced this with the actual index that i got from the "inFixedValues" parameter of the classify function everything worked.

    Also i was able to deproxify just by changing the src IP and port without changing the checksum.

    Thanks a lot for all the help.

    Aravind
    • Marked as answer by arvind_trinity Thursday, August 27, 2009 5:34 AM
    Thursday, August 27, 2009 5:34 AM

All replies

  • Ideally you want to do the de-proxying from INBOUND_TRANSPORT_DISCARD layers. There are couple older threads on this topic which you can look them up.

    In either case recv-injection requires the cloned NBL to begin with the the IP header. Which means you will need to retreat the orginal NBL by the amount of inMetaValues->ipHeaderSize + inMetaValues->transportHeaderSize before you allocate the clone (and advance the same amount back when done).

    Now that the clone begins with IP header, you would then need to advance it by the amount of inMetaValues->ipHeaderSize to get to the TCP header. Then you can use NdisGetDataBuffer to get to the actual pointer.

    Before you can inject the modified clone, you will need to retreat the same amount back to put the NBL back to the beginning of IP header.

    Hope this helps,
    Biao.W.
    Friday, August 21, 2009 11:11 PM
  • Thanks a lot Baio.W

    I did exactly as you said but still i am unable to get it work.
    Do i have to change the IP and TCP checksum.

    Aravind

    Saturday, August 22, 2009 6:24 PM
  • If you modified anything, then you will need to recalculate the checksum(s).

    Additionally, you may find the information from the following of use:

       http://msdn.microsoft.com/en-us/library/aa938504.aspx

    Hope this helps


    Dusty Harper [MSFT]
    Microsoft Corporation
    ------------------------------------------------------------
    This posting is provided "AS IS", with NO warranties and confers NO rights
    ------------------------------------------------------------
    Monday, August 24, 2009 6:00 PM
    Moderator
  • Hi

    Sorry my mistake. First of all my IP layer injection is not working!

    This is what i did in case there is a checksum error then the packet must be sent to any of the discard layers. So i defined callouts in both trans and n/w layers but couldn get the discarded packet!!!.

    The bug is i was trying to create a injection handle for transport layer and was trying to use it in n/w layer.
    So i modified my code to get a new error!

    status = FwpsInjectionHandleCreate0(

    AF_UNSPEC,

    FWPS_INJECTION_TYPE_TRANSPORT | FWPS_INJECTION_TYPE_NETWORK,

    &gInjectionHandle

    );

    gives me error "the parameter is incorrect" when i try to run the driver.
    So i need to create a injection handle using which i can inject from both N/W and transport layers.
    Plz help.

    NOTE: I am using Win7 on x86

    Tuesday, August 25, 2009 3:35 AM
  • Hi,

    Instead of asking small questiones i ll let know the entire work i did so far:

    I took "inspect" sample from WDK and started to modify it for tcp transparent proxying (first for a single site).

    -- i removed all the ALE callouts and had only TRASPORT in/out bound callouts with condition to catch all tcp packets
    -- the classify will queue all the packets for a worker thread to process.
    -- in outbound reinject function i will check whether the packet is for a particular addr and port, in which case i ll get the tcp header and modify the port to new port.
    -- then while re-injecting assign the new addr to the sendArgs.remoteAddress
    NO checksum modification is done as its been said that transport-reinject will do it.

    lets assume this all worked fine.

    -- Now in the inbound path i registered a callout at IP layer to catch packets with ip equal to the address i assigned before
    -- then the packet is queued for the worker thread to process.
    -- in IP reinject function i would retreat the packet to ipheader size and then clone the packet.
    -- then advance the header by ip header size and get the tcp header.
    -- modify the src port of the tcp header.
    -- then retreat the packet by ip header size and get the ip header.
    -- modify the src address of the ip header to original address.
    -- now reinject the packet using FwpsInjectNetworkReceiveAsync0

    but after reinjecting the connection doesnot happen. Also i couldn see the reinjected packet at inbound transport layer or inbound transport discard layer. But the injection fn returns a success status.

    Plz let me know anything that i have missed or made mistake. Also help me in debugging possible errors as i am stuck in this for a loooong time.

    Also one strange thing that i could see is that the ACK bit of the tcp header as i see in inbound IP layer is "0". I am not sure why?

    Aravind
    Tuesday, August 25, 2009 11:37 AM
  • In the inbound path, you will need to recalulate both ipChecksum and transport header checksum before you inject the packet.

     Also with respect to your earlier post, i'm assuming that you aldready figured out that you will need to create separate injection handles to inject at the transport and network layers.


    Anu
    Tuesday, August 25, 2009 6:27 PM
  • Hi Anu,

    Thanks a lot, will work on checksum.

    It seems that normal clone-inject (without any modification) in inbound ip layer doesn't seem to work for me.

    this is what i did:

    1) registered a callout for inbound IP layer to catch packets that belong to a particular src IP.
    2) queued the packet for a worker thread to process and block-absorbed the original packet.

    void
    InspectIpClassify(
       IN const FWPS_INCOMING_VALUES0* inFixedValues,
       IN const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,
       IN OUT void* layerData,
       IN const FWPS_FILTER0* filter,
       IN UINT64 flowContext,
       OUT FWPS_CLASSIFY_OUT0* classifyOut
       )
    {
     //declerations
     UINT32 ipv4;
     UCHAR *ip;
     KLOCK_QUEUE_HANDLE connListLockHandle;
     KLOCK_QUEUE_HANDLE packetQueueLockHandle;

     INSPECT_PENDED_PACKET *pendedPacket = NULL;
     FWP_DIRECTION packetDirection;

     ADDRESS_FAMILY addressFamily;
     FWPS_PACKET_INJECTION_STATE packetState;
     BOOLEAN signalWorkerThread = FALSE;

     UNREFERENCED_PARAMETER(flowContext);
     UNREFERENCED_PARAMETER(filter); 

       //
       // We don't have the necessary right to alter the classify, exit.
       //
     if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
     {
      goto Exit;
     }

     ASSERT(layerData != NULL);

       //
       // We don't re-inspect packets that we've inspected earlier.
       //
     packetState = FwpsQueryPacketInjectionState0(
         gInjectionHandleIP,
         layerData,
         NULL
         );

     if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
      (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
     {
      classifyOut->actionType = FWP_ACTION_PERMIT;
      goto Exit;
     }

     addressFamily = AF_INET;

     packetDirection = FWP_DIRECTION_INBOUND;


     //do all the allocation logic here itself
     pendedPacket = ExAllocatePoolWithTag(
                            NonPagedPool,
                            sizeof(INSPECT_PENDED_PACKET),
                            INSPECT_PENDED_PACKET_POOL_TAG
                            );

     if (pendedPacket == NULL)
     {
      classifyOut->actionType = FWP_ACTION_BLOCK;
      classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
      goto Exit;
     }

     RtlZeroMemory(pendedPacket, sizeof(INSPECT_PENDED_PACKET));

     pendedPacket->type = INSPECT_DATA_PACKET;
     pendedPacket->direction = packetDirection;
     pendedPacket->ipPacket = TRUE;
     pendedPacket->addressFamily = AF_INET;
     pendedPacket->compartmentId = inMetaValues->compartmentId;
     pendedPacket->ipHeaderSize = inMetaValues->ipHeaderSize;
     pendedPacket->ipv4RemoteAddr = RtlUlongByteSwap(
      inFixedValues->incomingValue[FWPS_FIELD_INBOUND_IPPACKET_V4_IP_REMOTE_ADDRESS].value.uint32);

     if (layerData != NULL)
     {
      pendedPacket->netBufferList = layerData;
      FwpsReferenceNetBufferList0(pendedPacket->netBufferList, TRUE);
     }

     //TODO: Fill in other fields from metaData

       KeAcquireInStackQueuedSpinLock(
          &gConnListLock,
          &connListLockHandle
          );
       KeAcquireInStackQueuedSpinLock(
          &gPacketQueueLock,
          &packetQueueLockHandle
          );

       if (!gDriverUnloading)
       {
          signalWorkerThread = IsListEmpty(&gPacketQueue) &&
                               IsListEmpty(&gConnList);

          InsertTailList(&gPacketQueue, &(pendedPacket->listEntry));
          pendedPacket = NULL; // ownership transferred

          classifyOut->actionType = FWP_ACTION_BLOCK;
          classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
       }
       else
       {
          //
          // Driver is being unloaded, permit any connect classify.
          //
          signalWorkerThread = FALSE;

          classifyOut->actionType = FWP_ACTION_PERMIT;
       }

       KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
       KeReleaseInStackQueuedSpinLock(&connListLockHandle);

       if (signalWorkerThread)
       {
          KeSetEvent(
             &gWorkerEvent,
             0,
             FALSE
             );
       }
       //classifyOut->actionType = FWP_ACTION_PERMIT;

    Exit:

       if (pendedPacket != NULL)
       {
        DbgPrint("freeing pended packet\n");
          FreePendedPacket(pendedPacket);
       }

       return;
    }

    3) In the worker thread i called a clone - reinject function and injected the packet without doing any modification (after ensuring that the packet starts at the IP header).

    NTSTATUS status = STATUS_SUCCESS;

       NET_BUFFER_LIST* clonedNetBufferList = NULL;
       NET_BUFFER *netBuffer = NULL,*clonedNetBuffer = NULL;
       TCP_HEADER *tcp_header;
       IP_HEADER *ip_header;
       ULONG nblOffset;
       UINT32 *ipv4;
       UCHAR *addr,*addr1;
       UINT32 a,b;

       //
       // For inbound net buffer list, we can assume it contains only one
       // net buffer.
       //
       netBuffer = NET_BUFFER_LIST_FIRST_NB(packet->netBufferList);
       tcp_header = (TCP_HEADER*) NdisGetDataBuffer(netBuffer,sizeof(TCP_HEADER),NULL,sizeof(UINT16),0);

       //
       // Adjust the net buffer list offset to the start of the IP header.
       //
       NdisRetreatNetBufferDataStart(
          netBuffer,
          packet->ipHeaderSize,
          0,
          NULL
          );

       //
       // Note that the clone will inherit the original net buffer list's offset.
       //

       status = FwpsAllocateCloneNetBufferList0(
                   packet->netBufferList,
                   NULL,
                   NULL,
                   0,
                   &clonedNetBufferList
                   );

       //
       // Undo the adjustment on the original net buffer list.
       //

       NdisAdvanceNetBufferDataStart(
          netBuffer,
          packet->ipHeaderSize,
          FALSE,
          NULL
          );

       if (!NT_SUCCESS(status))
       {
          goto Exit;
       }

       clonedNetBuffer = NET_BUFFER_LIST_FIRST_NB(clonedNetBufferList);

       NdisAdvanceNetBufferDataStart(
          clonedNetBuffer,
          packet->ipHeaderSize,
          FALSE,
          NULL
          );

       if (!NT_SUCCESS(status))
       {
          goto Exit;
       }

       tcp_header = (TCP_HEADER *) NdisGetDataBuffer(
         clonedNetBuffer,
         sizeof(TCP_HEADER),
         NULL,
         sizeof(UINT16),
         0);

       DbgPrint("IP inject src port = %hu\n",RtlUshortByteSwap(tcp_header->srcPort));
       DbgPrint("IP inject dest port = %hu\n",RtlUshortByteSwap(tcp_header->destPort));
       DbgPrint("syn = %hu ack = %hu\n",tcp_header->SYN,tcp_header->ACK);
       DbgPrint("IP header size %u\n",packet->ipHeaderSize);

    //now the packet begins at the IP header
          NdisRetreatNetBufferDataStart(
          clonedNetBuffer,
          packet->ipHeaderSize,
          0,
          NULL
          );

       ip_header = (IP_HEADER *) NdisGetDataBuffer(
         clonedNetBuffer,
         sizeof(IP_HEADER),
         NULL,
         sizeof(UINT16),
         0);

       addr = (UCHAR *) &(ip_header->destAddr);
       DbgPrint("inject dest ADDR - %hu.%hu.%hu.%hu\n",addr[0],addr[1],addr[2],addr[3]);

       addr = (UCHAR *) &(ip_header->srcAddr);
       DbgPrint("inject src ADDR - %hu.%hu.%hu.%hu\n",addr[0],addr[1],addr[2],addr[3]);


       status = FwpsInjectNetworkReceiveAsync0(
                   gInjectionHandleIP,
                   NULL,
                   0,
                   packet->compartmentId,
                   FWPS_FIELD_INBOUND_IPPACKET_V4_INTERFACE_INDEX,
                   FWPS_FIELD_INBOUND_IPPACKET_V4_SUB_INTERFACE_INDEX,
                   clonedNetBufferList,
                   MobicipInjectComplete,
                   packet
                   );

       if (!NT_SUCCESS(status))
       {
        DbgPrint("Injection FAILED!!!\n");
          goto Exit;
       }

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

    Exit:

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

       return status;
    }

    4) This is how i created the injection handle.

    status = FwpsInjectionHandleCreate0(
                   AF_INET,
                   FWPS_INJECTION_TYPE_NETWORK,
                   &gInjectionHandleIP
                   );

       if (!NT_SUCCESS(status))
       {
        DbgPrint("Network handle creation FAILED\n");
          goto Exit;
    }

    This doesn't seem to work. Plz plz help i am stuck in this for a long time.
    Also plz let me know if there is any sample code for ip injection...

    Aravind

    Wednesday, August 26, 2009 3:06 AM
  • Hi,

    Sorry again my mistake. The error is

    status = FwpsInjectNetworkReceiveAsync0(
                   gInjectionHandleIP,
                   NULL,
                   0,
                   packet->compartmentId,
                   FWPS_FIELD_INBOUND_IPPACKET_V4_INTERFACE_INDEX,
                   FWPS_FIELD_INBOUND_IPPACKET_V4_SUB_INTERFACE_INDEX,
                   clonedNetBufferList,
                   MobicipInjectComplete,
                   packet
                   );
    in this highlighted part. When i replaced this with the actual index that i got from the "inFixedValues" parameter of the classify function everything worked.

    Also i was able to deproxify just by changing the src IP and port without changing the checksum.

    Thanks a lot for all the help.

    Aravind
    • Marked as answer by arvind_trinity Thursday, August 27, 2009 5:34 AM
    Thursday, August 27, 2009 5:34 AM