项目的需求背景:
早先的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;
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;
首先,自然是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的连接。
欢迎交流探讨!