How to Modify Packet In OUTBOUND_TRANSPORT_LAYER_V4

i am deng.

i want to modify tcp header data.

i readhttp://msdn2.microsoft.com/en-us/library/aa938500.aspx

Inline packet Modification from Outbound Transport Layers

i dont know how to set the tlSendArgs->remoteAddress value.

sample said:

//
// TODO: Allocate and populate tlSendArgs using information from
// inFixedValues and inMetaValues.
// Note: 1) Remote address and controlData (if not NULL) must
// be deep-copied.
// 2) IPv4 address must be converted to network order.
// 3) Handle allocation errors.

//here


ASSERT(tlSendArgs != NULL);

i wrote:

tlSendArgs=(FWPS_TRANSPORT_SEND_PARAMS0*) ExAllocatePoolWithTag(NonPagedPool, sizeof(FWPS_TRANSPORT_SEND_PARAMS0),TAG_SEND_ARGS);
//tlSendArgs->remoteAddress=? where can i get the value &convert it to network order

memcpy(&tlSendArgs->remoteScopeId,&inMetaValues->remoteScopeId,sizeof(SCOPE_ID));
memcpy(tlSendArgs->controlData,inMetaValues->controlData,inMetaValues->controlDataLength);
tlSendArgs->controlDataLength=inMetaValues->controlDataLength;

when it starts to do Inject,blueScreen happened.

status = FwpsInjectTransportSendAsync0(
gInjectionHandle,
NULL,
inMetaValues->transportEndpointHandle,
0,
tlSendArgs,
AF_INET,//af
inMetaValues->compartmentId,
clonedNetBufferList,
InjectionCompletionFn,
NULL); //tlSendArgs

Sample Said:
// Note: For TCP traffic, FwpsInjectTransportSendAsync0
// must be queued and run by a DPC.
how should i code it or write code for it.

i need your help.

[1992 byte] By [DengTianyu] at [2008-1-26]
# 1

Hi Deng,

Here are some topics in the MSDN that will help understanding DPC objects for drivers.

DPC Objects and DPCs

http://msdn2.microsoft.com/en-us/library/ms795093.aspx

KeInitializeDpc

http://msdn2.microsoft.com/en-us/library/ms801637.aspx

KeInsertQueueDpc

http://msdn2.microsoft.com/en-us/library/ms801922.aspx

For the remote address, you can extract it from the FWPS_INCOMING_VALUES0 inFixedValues struct passed to the classifyFn. The index into the struct will depend on the layer you are doing this at.

For example at the V4 outbound transport layer, you can get it from :

inFixedValues->incomingValue[FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS].value.uint32

To convert byte ordering for IPv4 address you could use:

RtlUlongByteSwap:

http://msdn2.microsoft.com/en-us/library/ms802967.aspx

Keep in mind that tlSendArgs->controData is only a pointer and will need its own memory allocation and deep copy if the inMetaValues->controlData is not NULL.

Please let us know if you have any futher questions.

Thanks,

Omer.

OmerHashmi-MSFT at 2007-9-28 > top of Msdn Tech,Windows Networking Development,Windows Filtering Platform (WFP)...
# 2

Hi Deng,

You should actually be queuing a DPC for both FwpsInjectTransportSendAsync0 and for FwpsInjectTransportReceiveAsync0 Apis if you are injecting from within the classify function. This error on msdn should be fixed soon.

thanks.

AnupamaVasanth[MSFT] at 2007-9-28 > top of Msdn Tech,Windows Networking Development,Windows Filtering Platform (WFP)...
# 3

Mr. omer.

Thank you very much. you gave me so much informations.

1. i got the IPv4 as you said .IPv4 address must be converted to network order.

tlSendArgs->remoteAddress UCHAR*

if i should add "." between the digital value. 127.0.0.1 or 127001

2. i read the dpc documents. really i dont know how to add "FwpsInjectTransportSendAsync0" to a DPC Queue and how can

get the result (success or failure)

i tried to do it like following code:

IN a driver:

typedef struct _DPCTransportSendAsync0 {
HANDLE injectionHandle;
HANDLE injectionContext;
UINT64 endpointHandle;
UINT32 flags;
FWPS_TRANSPORT_SEND_PARAMS0 *sendArgs;
ADDRESS_FAMILY addressFamily;
COMPARTMENT_ID compartmentId;
NET_BUFFER_LIST *netBufferList;
FWPS_INJECT_COMPLETE0 completionFn;
HANDLE completionContext;
}DPCTransportSendAsync0;

PRKDPC gDpc;
VOID MyCustomDpc(IN struct _KDPC *Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2);

//initilize the gDpc at entry of a driver.

Drvier_Entry(){

...

KeInitializeDpc(gDpc,JmcCustomDpc,deviceObject);
...

}

VOID MyCustomDpc(IN struct _KDPC *Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2)
{

DPCTransportSendAsync0 *pDPCTransportSendAsync0
= (DPCTransportSendAsync0*)SystemArgument1;
NTSTATUS status;

status = FwpsInjectTransportSendAsync0(
pDPCTransportSendAsync0->injectionHandle,
NULL,
pDPCTransportSendAsync0->endpointHandle,
0,
pDPCTransportSendAsync0->sendArgs,
AF_INET,//af
pDPCTransportSendAsync0->compartmentId,
pDPCTransportSendAsync0->netBufferList,
pDPCTransportSendAsync0->completionFn,
NULL);

}

ClassifyFn()[

DPCTransportSendAsync0 pDPCTransportSendAsync0;

....

pDPCTransportSendAsync0.injectionHandle=gInjectionHandle;
pDPCTransportSendAsync0.injectionContext=NULL;
pDPCTransportSendAsync0.endpointHandle=inMetaValues->transportEndpointHandle;
pDPCTransportSendAsync0.flags=0;
pDPCTransportSendAsync0.sendArgs=tlSendArgs;
pDPCTransportSendAsync0.addressFamily=AF_INET;
pDPCTransportSendAsync0.compartmentId=inMetaValues->compartmentId;
pDPCTransportSendAsync0.netBufferList=clonedNetBufferList;
pDPCTransportSendAsync0.completionFn=InjectionCompletionFn;
pDPCTransportSendAsync0.completionContext=NULL;

KeInsertQueueDpc(gDpc,&pDPCTransportSendAsync0,NULL);

/*
status = FwpsInjectTransportSendAsync0(
gInjectionHandle,
NULL,
inMetaValues->transportEndpointHandle,
0,
tlSendArgs,
AF_INET,//af
inMetaValues->compartmentId,
clonedNetBufferList,
InjectionCompletionFn,
NULL); //tlSendArgs

if (!NT_SUCCESS(status))
*/

// how can i get the result of Dpc because i should know it to prevent errors.

}

when i start the driver,a bluescreen happened. give me some advices more please.

DengTianyu at 2007-9-28 > top of Msdn Tech,Windows Networking Development,Windows Filtering Platform (WFP)...
# 4

1. WFP only accepts IP addresses in numeric (or binary) form, so don't insert dots in the address. You are indicated a 4-byte IPv4 address in host order, and you can use htonl() or RtlUlongByteSwap() function to convert it to network order.

2. A couple things to note --

a) DPCs don't get executed in the same thread context as classifyFn(), they gets run only when the processor IRQL drops below DISPATCH_LEVEL. Since classifyFn() typically runs at DISPATCH_LEVEL, your DPC routines are almost always deferred. That's why DPCs are called "Deferred" Procedures.

b) Since DPCs are deferred, it is possible that you will be indicated multiple packets before you DPC gets a chance to run. Therefore you can not use one gloabl DPC structure to process them. So you need to have one DPC structure allocated for each packet. Hence you structure needs to be --

typedef struct _DPCTransportSendAsync0 {

KDPC injectionDpc;// you need to embed the KDPC "structure", not just the

// PKDPC pointer -- because Ke*Dpc functions require

// you to supply space.
HANDLE injectionHandle;
HANDLE injectionContext;
UINT64 endpointHandle;

...

}

c) Since DPC will get run from another thread context, you *must* allocate DPCTransportSendAsync0 structure from a pool. Your code in your post places the structure on the stack, that's not good because once classifyFn returns, your structure is destroyed. And later on when DPC gets to run, it will be touching freed memory. That's why you are getting a bluescreen.

Once the structure is allocated, you call

KeInitializeDpc(&pDPCTransportSendAsync0->injectionDpc,

MyCustomDpc,

pDPCTransportSendAsync0);

And then you call KeInsertQueueDpc to schedule your DPC.

From your MyCustomDpc function, you get back pDPCTransportSendAsync0 from "DeferredContext" (not SystemArgument1).

d) As Omer pointed out earlier, you will need to allocate space from pool to store the ControlData (if not NULL) as well as the swapped remote address. Once you return from classifyFn, WFP will reclaim the memory associated with those fields.

e) Error handling is performed within the DPC routine. Once you queued the DPC, you will need to return BLOCK (and set the ABORB field) from classifyFn.

Hope this helps,

Biao.W.

BiaoWang[MSFT] at 2007-9-28 > top of Msdn Tech,Windows Networking Development,Windows Filtering Platform (WFP)...
# 5

Mr. Biao.W.

Thanks a lot for your reply.

Following your advice,I modified my code,

but i found in my driver it seems that Using KeInitializeDpc Function will cause a blueScreen.

As a test.i defined a global dpc;

KDPC gDpc;

even out of ClassfyFunction, for example. after RegisterCallout()

when i call KeInitializeDpc like this:

myRegisterCallout(){

//...

RegisterCallout();

//..

KeInitializeDpc(&gDpc,MyCustomDpc,NULL);

}

// even myDpc Function do nothing.

VOID MyCustomDpc(IN struct _KDPC *Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2)
{

DoTraceMessage(TRACE_FLOW_ESTABLISHED,"MyCustomDpc OK.\r\n");

}

if when i use dpc in a driver,i should use KeSetTimer() or other routine needs.

DengTianyu at 2007-9-28 > top of Msdn Tech,Windows Networking Development,Windows Filtering Platform (WFP)...
# 6

Hi,

Can you tell us what the Bugcheck code (or output from !analyze -v) is when you get a blue screen?

Thanks

Omer.

OmerHashmi-MSFT at 2007-9-28 > top of Msdn Tech,Windows Networking Development,Windows Filtering Platform (WFP)...
# 7

Mr. omer.

thank you very much.

i am very sorry i had a mistake in another place. when i debug the dump file i found the place.

it wants to release a NULL pool memory.

DengTianyu at 2007-9-28 > top of Msdn Tech,Windows Networking Development,Windows Filtering Platform (WFP)...
# 8

Hi,

i am deng. i successed in modifying packet in outbound_transport_layer.

in InjectionCompletionFn,the Status is OK. in the server,i found the packet with our flag in TCP Header.

but i have a question about checksum.

i found in the clonednetBuffer,tcpHeader[16],tcpHeader[17] are always 0,0.

after modify tcp header i re-caluate the checksum using checksum() & PSD_HEADER.

i confirmed it is modified in clonedNetBuffer before executing dpc(FwpsInjectTransportSendAsync0)

but InjectionCompletionFn i found In netBufferList,the TCP header's checksum are always ff,ff (tcp[16],tcp[17])

NDIS_TCP_IP_CHECKSUM_PACKET_INFO ChecksumInfo;

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

the ChecksumInfo.Value is always zero.

How should i get the original checksum value and reset the new checksum?

DengTianyu at 2007-9-28 > top of Msdn Tech,Windows Networking Development,Windows Filtering Platform (WFP)...
# 9

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.

Biao.W.

BiaoWang[MSFT] at 2007-9-28 > top of Msdn Tech,Windows Networking Development,Windows Filtering Platform (WFP)...
# 10

Mr. Biao.W.

Thanks a lot.

i confirmed it,WFP Corrects the checksum.

DengTianyu at 2007-9-28 > top of Msdn Tech,Windows Networking Development,Windows Filtering Platform (WFP)...
# 11

Information in this post has been very useful, but I have a few clarifications I would appreciate if someone can answer:

- Anu said "you should actually be queuing a DPC for both FwpsInjectTransportSendAsync0 and for FwpsInjectTransportReceiveAsync0 Apis if you are injecting from within the classify function. This error on msdn should be fixed soon."

In the context of Deng's original query about Outbound Transport Layer, can someone confirm both Send/Receive Apis are to to be invoked in the outbound direction via 2 DPCs ? Or did the post mean FwpsInjectTransportSendAsync0() needs invoked in Outbound and FwpsInjectTransportReceiveAsync0 in inbound - which would seem more intuitive.

Other query is in regards to the freeing of FWPS_TRANSPORT_SEND_PARAMS0's remoteAddress and controlData variables, allocated as a result of doing a deep copy in classify().

Biao said "you will need to allocate space from pool to store the ControlData (if not NULL) as well as the swapped remote address. Once you return from classifyFn, WFP will reclaim the memory associated with those fields"

WDK says this in regards to FWPS_TRANSPORT_SEND_PARAMS0: "If socket control data, is not NULL, it must be deep-copied in the callout's implementation of the classifyFn function, and the controlData buffer must be kept valid until the injection completion function is called."

- To me this implies that I need to free the data in the completion function, also outbound transport modification sample in MSDN has this comment in the completion function "TODO: Free tlSendArgs and embedded allocations.".

I am aware that some of the MSDN information is inaccurate in this area so appreciate some clarification from a member of the WFP team.

Thanks,

Nic

nidoyle at 2007-9-28 > top of Msdn Tech,Windows Networking Development,Windows Filtering Platform (WFP)...
# 12

nidoyle wrote:

...can someone confirm both Send/Receive Apis are to to be invoked in the outbound direction via 2 DPCs ? Or did the post mean FwpsInjectTransportSendAsync0() needs invoked in Outbound and FwpsInjectTransportReceiveAsync0 in inbound - which would seem more intuitive.

It is latter. Note that the DPC requirement applies to TCP traffic only. To ensure ordered delivery of data, the TCP stack indicates data to callouts with a spinlock held. If data was to injected back from within the classifyFn, a deadlock will ensure and hence the requirement to inject data back via queueing DPCs.

nidoyle wrote:

...To me this implies that I need to free the data in the completion function, ..."

That is correct. you can use the completion context to keep track these allocations and free them upon completion.

Thanks,

Biao.W.

BiaoWang[MSFT] at 2007-9-28 > top of Msdn Tech,Windows Networking Development,Windows Filtering Platform (WFP)...
# 13

Thanks for the clarifications Biao.

Nic

nidoyle at 2007-9-28 > top of Msdn Tech,Windows Networking Development,Windows Filtering Platform (WFP)...