WFP实现的端口复用

背景

部分服务器只开80/443端口,那么只往服务器的80/443发送数据,而有的情况下,我们需要在内部监听一个9999端口,怎么让数据能正常通过80然后到9999呢?

利用

驱动使用的是WinDivert,开源,之前的blog有相关的介绍。

代码如下,作为demo只处理80端口。

简单说一下,tcp连接都会先进行三次握手,我们刻意开的9999端口和默认开启的80端口都是基于tcp协议的,怎么分辨我们的特殊数据呢?这里比较随意(改成异或或者位移不难吧?),当第一位是字符1的时候,就认为是需要转发到9999的数据,这里不能直接转发到9999,必须要先给80发一个rst中止连接。

为什么?因为我们收到特殊数据的时候80和你的客户端已经完成了三次握手,你和9999都完全没有握手。tcp是可靠的协议,在没有和9999握手的前提下,直接发数据9999是不会理你的,所以我们先中止和80的连接,记录下src的ip,当你下一次来的时候,直接发往9999进行三次握手和数据传输。

#include <winsock2.h>
#include <windows.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include "windivert.h"

#define MAXBUF          WINDIVERT_MTU_MAX

typedef struct
{
	WINDIVERT_IPHDR  ip;
	WINDIVERT_TCPHDR tcp;
} PACKET, * PPACKET;

void PacketInit(PPACKET packet)
{
	memset(packet, 0, sizeof(PACKET));
	packet->ip.Version = 4;
	packet->ip.HdrLength = sizeof(WINDIVERT_IPHDR) / sizeof(UINT32);
	packet->ip.Length = htons(sizeof(PACKET));
	packet->ip.TTL = 64;
	packet->ip.Protocol = IPPROTO_TCP;
	packet->tcp.HdrLength = sizeof(WINDIVERT_TCPHDR) / sizeof(UINT32);
}

BOOLEAN g_ok = FALSE;
int main()
{
	PACKET reset0;
	PPACKET reset = &reset0;
	PacketInit(reset);
	reset->tcp.Rst = 1;
	reset->tcp.Ack = 1;
	UINT32 pyloadIP = NULL;

	PVOID payload = NULL;
	UINT payload_len = NULL;
	UINT packet_len = NULL;
	unsigned char packet[MAXBUF];
	WINDIVERT_ADDRESS addr = { 0 };
	PWINDIVERT_IPHDR ip_header = NULL;
	PWINDIVERT_TCPHDR tcp_header = NULL;


	HANDLE handle = WinDivertOpen(" tcp.DstPort == 80 or tcp.SrcPort == 9999", WINDIVERT_LAYER_NETWORK, 0, 0);

	if (handle == INVALID_HANDLE_VALUE)
		return 0;

	while (1)
	{
		//这里一直在接收数据包
		if (!WinDivertRecv(handle, packet, sizeof(packet), &packet_len, &addr))
		{
			printf("failed to read packet (%d) \n", GetLastError());
			continue;
		}
		WinDivertHelperParsePacket(packet, packet_len, &ip_header, NULL, NULL, NULL, NULL, &tcp_header, NULL, &payload, &payload_len, NULL, NULL);
		if (ip_header == NULL || tcp_header == NULL)
		{
			printf("failed to parse packet (%d) \n", GetLastError());
			continue;
		}

		char* buf = (char*)payload;
		if (payload && buf[0] == '1' &&  !pyloadIP)
		{
			if (!addr.Outbound)
			{
				//首先中止第一个连接	-->告诉80端口已经结束了
				reset->ip.SrcAddr = ip_header->SrcAddr;
				reset->ip.DstAddr = ip_header->DstAddr;
				reset->tcp.SrcPort = tcp_header->SrcPort;
				reset->tcp.DstPort = htons(80);
				reset->tcp.SeqNum = tcp_header->SeqNum;
				reset->tcp.AckNum = tcp_header->AckNum;
				WinDivertHelperCalcChecksums((PVOID)reset, sizeof(PACKET), &addr, 0);
				if (!WinDivertSend(handle, (PVOID)reset, sizeof(PACKET), NULL, &addr))
				{
					printf("error reset\n");
				}
				pyloadIP = ip_header->SrcAddr;
			}
			continue;
		}

		//这里将端口重定向
		if (pyloadIP && (pyloadIP == ip_header->SrcAddr || pyloadIP == ip_header->DstAddr))
		{
			if (addr.Outbound)
			{
				if (tcp_header->SrcPort == htons(9999))
				{
					tcp_header->SrcPort = htons(80);
				}
			}
			else
			{
				if (tcp_header->DstPort == htons(80))
				{
					tcp_header->DstPort = htons(9999);
				}
			}
		}

		WinDivertHelperCalcChecksums(packet, packet_len, &addr, 0);
		UINT writeLen = NULL;
		if (!WinDivertSend(handle, packet, packet_len, &writeLen, &addr))
		{
			printf("failed to send packet (%d) \n", GetLastError());
			continue;
		}

	}

	return 0;
}

client测试代码

#include<stdio.h>
#include<windows.h>
#include<winsock.h>

#define SERVERPORT 80
#define SERVERIP "192.168.1.2"
#pragma comment(lib,"ws2_32.lib")

int main(int argc, char* argv[])
{
	struct sockaddr_in serAddr;
	SOCKET cliSocket;
	int conn;
	WSADATA Ws;
	char sendBuf[1024];
	int sen;
	int recvR;
	fd_set rfds;/
	struct timeval time;///
	int maxrd = 0;
	int ret;/

	if (WSAStartup(MAKEWORD(2, 2), &Ws) != 0)
	{
		printf("init windows socket failed:%d\n", GetLastError());
		return -1;
	}

	cliSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (cliSocket == INVALID_SOCKET)
	{
		printf("window socket failed:%d\n", GetLastError());
		return -1;
	}

	serAddr.sin_family = AF_INET;
	serAddr.sin_addr.s_addr = inet_addr(SERVERIP);
	serAddr.sin_port = htons(SERVERPORT);
	memset(serAddr.sin_zero, 0x00, 8);

	conn = connect(cliSocket, (struct sockaddr*) & serAddr, sizeof(serAddr));
	if (conn == SOCKET_ERROR)
	{
		printf("connect socket failed:%d\n", GetLastError());
		return -1;
	}
	else
	{
		printf("connect successfully!\n");
	}
	while (true)
	{
		FD_ZERO(&rfds);/
		FD_SET(0, &rfds);/
		FD_SET(cliSocket, &rfds);/
		time.tv_sec = 1;/
		time.tv_usec = 0;//
		maxrd = ((maxrd > cliSocket) ? maxrd : cliSocket);
		ret = select(maxrd + 1, &rfds, NULL, NULL, &time);
		if (ret == 0)
			continue;
		else {
			if (FD_ISSET(0, &rfds))
			{
				memset(sendBuf, 0x00, sizeof(sendBuf));
				
				system("pause");
				sen = send(cliSocket, "111111199999", (int)strlen("111111199999"), 0);
				if (sen == SOCKET_ERROR)
				{
					printf("send info error:%d\n", GetLastError());
					break;
				}
			}
			if (FD_ISSET(cliSocket, &rfds))
			{
				memset(sendBuf, 0x00, sizeof(sendBuf));
				recvR = recv(cliSocket, sendBuf, 1024, 0);
				printf("recieve from server:%s\n", sendBuf);
			}
		}

	}
	closesocket(cliSocket);
	WSACleanup();
	return 0;
}

server的测试代码

#include<windows.h>
#include<stdio.h>
#include<winsock.h>

#define SERVER_PORT 80
#define SERVER_IP  "0.0.0.0"
#pragma comment(lib,"ws2_32.lib")

DWORD Demo()
{

	SOCKET serSocket, cliSocket;
	struct sockaddr_in localAddr, clientAddr;
	WSADATA Ws;
	int Bit;
	int Lit;
	char recvBuf[1024];
	int recvR, sen;
	int cliLen;
	fd_set rfds;//
	struct timeval time;//
	int maxrd = 0;//
	int ret;//

	if (WSAStartup(MAKEWORD(2, 2), &Ws) != 0)
	{
		printf("init windows socket failed:%d\n", GetLastError());
		return -1;
	}
	serSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (serSocket == INVALID_SOCKET)
	{
		printf("create socket failed:%d\n", GetLastError());
		return -1;
	}
	localAddr.sin_family = AF_INET;
	localAddr.sin_port = htons(SERVER_PORT);
	localAddr.sin_addr.s_addr = inet_addr(SERVER_IP);
	memset(localAddr.sin_zero, 0x00, 8);

	Bit = bind(serSocket, (struct sockaddr*) & localAddr, sizeof(localAddr));
	if (Bit != 0)
	{
		printf("bind failed:%d\n", GetLastError());
		return -1;
	}
	Lit = listen(serSocket, 5);
	if (Lit != 0)
	{
		printf("listen failed:%d\n", GetLastError());
		return -1;
	}
	printf("server has been startup\n");
	while (true)
	{
		cliLen = sizeof(clientAddr);
		cliSocket = accept(serSocket, (struct sockaddr*) & clientAddr, &cliLen);
		if (cliSocket == INVALID_SOCKET)
		{
			printf("accept failed:%d\n", GetLastError());
			return -1;
		}
		//printf("client connect%d:%d\n", inet_ntoa(clientAddr.sin_addr), clientAddr.sin_port);/
		while (true)
		{
			FD_ZERO(&rfds);///
			FD_SET(0, &rfds);
			FD_SET(cliSocket, &rfds);
			time.tv_sec = 1;
			time.tv_usec = 0;/
			maxrd = (maxrd > cliSocket ? maxrd : cliSocket);/
			ret = select(maxrd + 1, &rfds, NULL, NULL, &time);

			if (ret == 0)//
				continue;
			else {
				if (FD_ISSET(0, &rfds))
				{ /
					memset(recvBuf, 0x00, sizeof(recvBuf));
					recvR = recv(cliSocket, recvBuf, 1024, 0);
					if (recvR == 0 || recvR == SOCKET_ERROR)
					{
						printf("the client had quit\n");
						break;
					}
					printf("recieve message:%s\n", recvBuf);
				}

				if (FD_ISSET(cliSocket, &rfds))
				{
					memset(recvBuf, 0x00, sizeof(recvBuf));
					//gets(recvBuf);
					sen = send(cliSocket, "19999", sizeof("19999"), 0);
				}
			}
		}
		return 0;
	}
	closesocket(serSocket);
	closesocket(cliSocket);
	WSACleanup();
	return 0;
}

int main()
{
	Demo();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值