使用windows filter platform(wfp)开发TCP重定向的方法

项目的需求背景:

早先的lsp模型做的TCP重定向功能,由于某些不知名的原因(懒得去排查了),会和其他相同的lsp模型开发的软件有冲突,也不支持ie11,所以决定使用微软新的winsock驱动模型wfp来实现TCP的重定向,为了加深理解和记忆,也和其他朋友分享心得,将开发流程记于此。

TCP的重定向功能需要将将要重定向的ip规则先添加到wfp驱动中,定义结构体如下:

typedef struct _tagTcpRule 
{
	unsigned long	NetbyteStartIP;
	unsigned long	NetbyteEndIP;
	unsigned short	NetbyteStartPort;
	unsigned short	NetbyteEndPort;
	int		ResID;
}TcpRule,*PTcpRule;

typedef struct _tagTcpMultiRule 
{
	TcpRule			MutltiRule[TCPRULES_BUFFER_LENGTH];
	unsigned long		RulesCount;
	unsigned long		RulesCapacity;
}TcpMultiRule,*PTcpMultiRule;

这个用来保存将要添加的ip和端口,同时也用于应用层和驱动层传输数据。在驱动层,定义如下结构体保存数据:

typedef struct _tagIPPortList 
{
	LIST_ENTRY	listEntry;
	UINT32 NetbyteStartIP;
	UINT32 NetbyteEndIP;
	UINT16 NetbyteStartPort;
	UINT16 NetbyteEndPort;
}IPPortList ,*PIPPortList ;

///应用程序向驱动写入数据时,存放于此
typedef struct _tagMULTI_TUNNEL_RULES_LIST 
{
	KSPIN_LOCK	RulesListLock;
	size_t		RulesCapacity;
	IPPortList 	MultiRules;
}MULTI_TUNNEL_RULES_LIST,*PMULTI_TUNNEL_RULES_LIST;

下面介绍wfp驱动层的开发流程,参考http://msdn.microsoft.com/en-us/library/windows/hardware/ff571005(v=vs.85).aspx 点击打开链接:

首先,自然是DriverEntry的开发,这个就是wdf驱动的一般流程,不再重复。

这里简单的把wfp的一些驱动函数写一下:

FwpsInjectionHandleCreate
FwpsInjectionHandleDestroy
FwpmEngineOpen
FwpmTransactionBegin
FwpmSubLayerAdd
FwpmTransactionCommit
FwpmTransactionAbort
FwpmEngineClose
FwpsCalloutUnregisterById
FwpmFilterAdd
FwpsCalloutRegister
FwpmCalloutAdd
FwpsQueryPacketInjectionState
详细说明在MSDN上都可以查到。下面重点说一下如何将TCP重定向:

1.注册FWPS_CALLOUT的classifyFn,这里直接是win7的版本,在MSDN上可以看到。layerKey设置为FWPM_LAYER_ALE_CONNECT_REDIRECT_V4,调用FwpsCalloutRegister等一系列的函数注册,然后调用FwpmFilterAdd添加要重定向或拦截的ip,端口,即完成规则的添加,之后当有数据连接到指定的ip时,就会调用classifyFn这里指定的函数。

2.FWPS_CONNECT_REQUEST这个结构体的解析,详细流程最好的就是我上面给的那个链接,win7和win8上要调用不同的函数,顺序不同,否则会失败。

3.在我的项目中,我将规则里的TCP重定向到了本地的service,所以ip指定为127.0.0.1,端口也是指向本地端口,这里要注意的是,按照微软的说法,重定向到本地服务时,还要指定服务的进程id,即

	if(INETADDR_ISANY((PSOCKADDR)&(pConnectRequest->localAddressAndPort)))
	{
		INETADDR_SETLOOPBACK((PSOCKADDR)&(pConnectRequest->remoteAddressAndPort));
	}
	else
	{
		INETADDR_SET_ADDRESS((PSOCKADDR)&(pConnectRequest->remoteAddressAndPort),
			INETADDR_ADDRESS((PSOCKADDR)&(pConnectRequest->localAddressAndPort)));
	}
	INETADDR_SET_PORT((PSOCKADDR)&pConnectRequest->remoteAddressAndPort,
		htons(SSL_PORT));
	if (ulServicePid)
	{
		pConnectRequest->localRedirectTargetPID = ulServicePid;
	}
至此,完成TCP的重定向,后面的数据转发不需要干涉,交由服务和应用进行。

这里简单的说一下,驱动层如何获取应用层通过DeviceIoControl传来的数据,注册WDF_IO_QUEUE_CONFIG的EvtIoDeviceControl,然后WdfIoQueueCreate创建队列,使用WdfRequestRetrieveInputMemory,WdfMemoryGetBuffer获取buffer里传来的数据,如果是应用层从驱动层读数据,则用WdfRequestRetrieveOutputBuffer获取缓冲区,成功后还需要调用WdfRequestCompleteWithInformation,否则应用层获取不到数据。

以上就是一个完整的wfp驱动重定向TCP的实现。只要添加了规则,本例程还可以重定向DNS的连接。
欢迎交流探讨!



你可能感兴趣的:(windows驱动)