背景

部分服务器只开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_MAXtypedef 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();
}

WFP实现的端口复用相关推荐

  1. [导入]C#中实现Socket端口复用

    一.什么是端口复用: 因为在winsock的实现中,对于服务器的绑定是可以多重绑定的,在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确则将包递交给谁,而且没有权限之分.这种多重绑定便称之为端口 ...

  2. linux socket 端口复用 SO_REUSEADDR

    下面建立的套接字都是tcp套接字 1.进程创建监听套接字socket1,邦定一个指定端口,并接受了若干连接.那么进程创建另外一个套接口socket2,并试图邦定同一个端口时候,bind错误返回&quo ...

  3. 端口复用及其实现分析[Google Patch]

    所谓绑定是指别人连接我只能通过我所绑定的端口,其实是说,你现在有这个端口开放了,人家可以连接到你的服务,也可以进行数据传输,但是也不一定要使用此端口进行传输,可能此端口只用于控制信息的传输 端口 = ...

  4. stm32之端口复用和重映射

    文章目录 端口复用 端口重映射 端口复用 WHAT IS 端口复用? 一个GPIO如果可以复用为内置外设的功能引脚,那么当这个GPIO作为内置外设使用的时候,就叫做复用 端口复用配置过程(以串口1位例 ...

  5. 【STM32】端口复用和重映射,完全重映射,部分重映射

    文章目录 端口复用 端口复用函数总结 端口重映射 完全重映射 完全重映射函数总结 部分重映射 端口复用 当 PA9,PA10 引脚作为串口 1 的 TX,RX 引脚使用的时候,那就是端口复用(相较于作 ...

  6. 端口复用和半关闭补充

    端口复用: int opt=1 : //设置端口复用 setsockopt(lfd,SOL_SOCKET,SO_REUSERADDR,(void *)&opt,sizeof(opt)); 半关 ...

  7. python监听多个udp端口_Python的Socket编程过程中实现UDP端口复用的实例分享

    关于端口复用 一个套接字不能同时绑定多个端口,如果客户端想绑定端口号,一定要调用发送信息函数之前绑定( bind )端口,因为在发送信息函数( sendto, 或 write ),系统会自动给当前网络 ...

  8. STM32 端口复用与重映射及低功耗引脚配置

    STM32 端口复用与重映射及低功耗引脚配置 什么是复用? 在TSM32里面,大部分的引脚都是有GPIO复用功能,也就是说,一个 GPIO如果可以复用为内置外设的功能引脚,那么当这个 GPIO 作为内 ...

  9. 端口复用突破防火墙(图)

    如何在溢出后得到安全的.隐蔽的Shell是大家一直都在讨论的问题,因为现在的防火墙和各种安全软件漫天飞,想不被它们发现还真是很难,幸好有很多牛人们用自己的实力探索出了一条这样的道路,让我们这些人能顺着 ...

最新文章

  1. 列出本地git仓库中的文件?
  2. Leetcode 122. 买卖股票的最佳时机 II 解题思路及C++实现
  3. 记下MD5验签可能出现的问题
  4. Java:汇总堆外数据
  5. 【学习笔记】第三章——内存 II(分页存储、快表与局部性原理、两级页表)
  6. 基于CompletableFuture并发任务编排实现
  7. java 开发书籍 目录_《零基础 Java 开发 》全书目录
  8. VS2012使用 MSDN教程
  9. 网站特效圈小猫游戏代码
  10. 计算机桌面变窄,电脑桌面图标变小怎么调整
  11. (转置矩阵)将一个3x3、4x4矩阵转置后输出
  12. OBIEE,OAS,OAC三者之间的区别
  13. 神经网络入门经典书籍,人工神经网络书籍推荐
  14. 股票-每日复盘-5-24
  15. 推荐一款快速生成海报的微信小插件
  16. 线性回归正则化 regularized linear regression
  17. 函数最值题目及答案_高一函数题目及答案解析
  18. 如何判断DLL是否注册过?
  19. Android 高版本 packageManager.getPackageArchiveInfo 总是返回null
  20. private、public、protected

热门文章

  1. 暗影精灵8 Pro 安装 Ubuntu20.04 问题记录
  2. 自建Ceph存储与 AWS、阿里云、腾讯云的成本对比
  3. python学习 day51之js续集
  4. 系统分析师的必备素质和技能
  5. [InnoDB] #CORRUPT LOG RECORD FOUND#[MySQL InnoDB表空损坏,数据库无法启动]#
  6. PO:更改数组与对象的配置
  7. 怼人神器(Windows)
  8. SSO(单点登录)技术漫谈
  9. 华硕P8H61-M+i3-3220 +GTX650
  10. jquery触屏幻灯片