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.
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.
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.
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.
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.
Hi,
Can you tell us what the Bugcheck code (or output from !analyze -v) is when you get a blue screen?
Thanks
Omer.
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.
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?
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.
Mr. Biao.W.
Thanks a lot.
i confirmed it,WFP Corrects the checksum.
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 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.
Thanks for the clarifications Biao.
Nic