端口转发

来源:互联网 发布:兰州知行学院官网 编辑:程序博客网 时间:2024/06/10 17:39
<pre name="code" class="cpp">/*端口映射PortTransfer_三种模式。(1) PortTransfer Port Dest_IP Port在运行本程序的计算机上监听Port端口,并将所有连接请求转到Dest_IP的Port去(2) PortTransfer ctrlIP ctrlPort Dest_IP Port和模式3配合用,程序将先主动连接ctrlIP:ctrlPort,之后所有在模式3的ServerPort端口的请求转到Dest_IP:Port去(3) PortTransfer ctrlPort ServerPort在执行模式2前先执行,将监听ctrlPort和ServerPort 端口,ctrlPort供模式2使用,ServerPort提供服务.模式1适合在网关上运行,将内网IP的端口映射到网关上,如:PortTransfer 88 192.168.0.110 80那么网关将开启88端口,所有在88端口的请求将转到内网的192.168.0.110的80端口模式2和模式3联合使用可以将内网的IP和端口映射到指定的IP和端口上,一般在公网IP(假设61.1.1.1)上执行模式3,如:PortTransfer 99 80, 80是映射过来的端口内网用户执行模式2如:PortTransfer 61.1.1.1 99 127.0.0.1 80,那么程序在内网将先连接61.1.1.1:99建立个连接,并等待接收命令。之后当61.1.1.1的80端口有请求,将通过99端口命令内网机子和公网机子建立条新的数据连接,并将请求通过新建的连接将请求转发到内网机.*/


#include <WINSOCK2.H>#include <windows.h>#include <stdio.h>#include <assert.h>#pragma comment(lib, "ws2_32.lib")#defineMAXBUFSIZE20480//接收缓冲大小#defineIPADDRSIZE32//IP地址大小#pragma pack(1)//socket结构struct SOCKINFO{SOCKET ClientSock;//客户端socketSOCKET ServerSock;//服务端socket};//目的结构struct ADDRESS{char DestszIP[IPADDRSIZE];WORD DestwPort;SOCKET  Destsock;};#pragma pack()////////A simple class of stack operator. code start.....template<typename T>class STACK{#define MAXSTACK 1024*2private:int top;T Data[MAXSTACK];public:STACK(){top = -1;}bool IsEmpty(){return top < 0;}bool IsFull(){return top >= MAXSTACK;}bool Push(T data){if(IsFull())return false;top++;Data[top] = data;return true;}T Pop(){return Data[top--];}};/////////////////////stack end//////////////////////////////////////////////////////////////////Transfer some Parameterstemplate<typename X, typename Y>class TransferParam{public:X GlobalData;STACK<Y> LocalData;public:TransferParam();virtual ~TransferParam();bool Push(Y data);Y Pop();};template<typename X, typename Y>TransferParam<X, Y>::TransferParam(){memset(this, 0, sizeof(TransferParam));}template<typename X, typename Y>TransferParam<X, Y>::~TransferParam(){}template<typename X, typename Y>bool TransferParam<X, Y>::Push(Y data){return LocalData.Push(data);}template<typename X, typename Y>Y TransferParam<X, Y>::Pop(){return LocalData.Pop(data);}/////////////////////////////////////////////////////转发到目的sockint DataSend(SOCKET Destsock, char *DataBuf, int DataLen){//参数效验assert(Destsock!=INVALID_SOCKET);assert(DataBuf!=NULL);assert(DataLen>0);if (Destsock==INVALID_SOCKET)return SOCKET_ERROR;if (DataLen<=0)return SOCKET_ERROR;if (DataBuf==NULL)return SOCKET_ERROR;//定义变量int nBytesLeft = DataLen;int nBytesSent = 0;int ret;int iMode = 0;//清除非堵塞套接字ioctlsocket(Destsock, FIONBIO, (u_long FAR*) &iMode);while(nBytesLeft > 0){ret = send(Destsock, DataBuf + nBytesSent, nBytesLeft, 0);if(ret <= 0)break;nBytesSent += ret;nBytesLeft -= ret;}return nBytesSent;}//在两个SOCKET中进行数据转发DWORD WINAPI TransmitData(LPVOID lParam){//参数效验SOCKINFO socks = *((SOCKINFO*)lParam);assert(lParam!=NULL);if (lParam==NULL)return FALSE;SOCKET ClientSock = socks.ClientSock;SOCKET ServerSock = socks.ServerSock;assert(ClientSock!=NULL);assert(ServerSock!=NULL);if (ClientSock==NULL)return FALSE;if (ServerSock==NULL)return FALSE;//定义变量char RecvBuf[MAXBUFSIZE] = {0};fd_set Fd_Read;int ret, nRecv;while(true){FD_ZERO(&Fd_Read);FD_SET(ClientSock, &Fd_Read);FD_SET(ServerSock, &Fd_Read);ret = select(0, &Fd_Read, NULL, NULL, NULL);if(ret <= 0)break;//客户端sockif(FD_ISSET(ClientSock, &Fd_Read)){//接收客户端数据nRecv = recv(ClientSock, RecvBuf, sizeof(RecvBuf), 0);if(nRecv <= 0)break;//转发到目的sockret = DataSend(ServerSock, RecvBuf, nRecv);if(ret <= 0 || ret != nRecv)break;}//服务端sockif(FD_ISSET(ServerSock, &Fd_Read)){nRecv = recv(ServerSock, RecvBuf, sizeof(RecvBuf), 0);if(nRecv <= 0)break;//转发到客户端sockret = DataSend(ClientSock, RecvBuf, nRecv);if(ret <= 0 || ret != nRecv)break;}}//关闭套接字closesocket(ClientSock);closesocket(ServerSock);return 0;}//连接到目的IP和端口SOCKET ConnectHost(DWORD DestdwIP, WORD DestwPort){//参数效验assert(DestdwIP>0);assert(DestwPort>0);if (DestdwIP<=0)return INVALID_SOCKET;if (DestwPort<=0)return INVALID_SOCKET;//创建socketSOCKET sockid;if ((sockid = socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET)return INVALID_SOCKET;//连接目的主机struct sockaddr_in srv_addr;srv_addr.sin_family = AF_INET;srv_addr.sin_addr.S_un.S_addr = DestdwIP;srv_addr.sin_port = htons(DestwPort);if (connect(sockid,(struct sockaddr*)&srv_addr,sizeof(struct sockaddr_in)) == SOCKET_ERROR){closesocket(sockid);return SOCKET_ERROR;}return sockid;}//连接到目的IP和端口SOCKET ConnectHost(char *DestszIP, WORD  DestwPort){//参数效验assert(DestszIP!=NULL);assert(DestwPort>0 && DestwPort<65535);if (DestszIP==NULL)return INVALID_SOCKET;if (DestwPort<=0 || DestwPort>=65535)return INVALID_SOCKET;// 转化地址DWORD dwServerIP = inet_addr(DestszIP);if (dwServerIP == INADDR_NONE){LPHOSTENT lpHost = gethostbyname(DestszIP);if (lpHost == NULL) return INADDR_NONE;dwServerIP = ((LPIN_ADDR)lpHost->h_addr)->s_addr;}//连接到目的IP和端口return ConnectHost(dwServerIP, DestwPort);}//在本机绑定sockSOCKET CreateSocket(DWORD dwIP, WORD wPort)//在dwIP上绑定wPort端口{//参数效验assert(wPort>0 && wPort<65535);if (wPort<0 || wPort>=65535)return INVALID_SOCKET;//创建socketSOCKET sockid;if ((sockid = socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET)return INVALID_SOCKET;//在本机绑定socketstruct sockaddr_in srv_addr = {0};srv_addr.sin_family = AF_INET;srv_addr.sin_addr.S_un.S_addr = dwIP;srv_addr.sin_port = htons(wPort);if (bind(sockid,(struct sockaddr*)&srv_addr,sizeof(struct sockaddr_in)) == SOCKET_ERROR){closesocket(sockid);return SOCKET_ERROR;}//监听链接listen(sockid,5);return sockid;}//模式一线程函数DWORD WINAPI PortTransfer_1(LPVOID lParam){//参数效验TransferParam<ADDRESS, SOCKET> *ConfigInfo = (TransferParam<ADDRESS, SOCKET>*)lParam;assert(ConfigInfo!=NULL);if (ConfigInfo==NULL)return FALSE;//定义变量SOCKET ClientSock, ServerSock;//出栈,获得客户的套接字ClientSock = ConfigInfo->LocalData.Pop();//先连接到目标计算机的服务ServerSock = ConnectHost(ConfigInfo->GlobalData.DestszIP, ConfigInfo->GlobalData.DestwPort);if(ServerSock <= 0){printf("connect RemoveHost Error.\r\n");closesocket(ClientSock);return FALSE;}printf("OK.\r\nStarting TransmitData\r\n");SOCKINFO socks;socks.ClientSock = ClientSock;//客户的套接字socks.ServerSock = ServerSock;//目标计算机服务的套接字//进入纯数据转发状态return TransmitData((LPVOID)&socks);}//模式一 本机监听端口,转发到目的IP,目的端口BOOL PortTransfer_1(WORD HostListenPort, char *szDestIP, WORD DestwPort){//参数效验assert(HostListenPort>0 && HostListenPort<65535);assert(szDestIP!=NULL);assert(DestwPort>0 && DestwPort<65535);if (HostListenPort<=0 || HostListenPort>=65535)return FALSE;if (szDestIP==NULL)return FALSE;if (DestwPort<=0|| DestwPort>=65535)return FALSE;//定义变量HANDLE hThread=NULL;DWORD dwThreadId=NULL;SOCKET AcceptSocket=NULL;TransferParam<ADDRESS, SOCKET> ConfigInfo;//设置变量memcpy(ConfigInfo.GlobalData.DestszIP,szDestIP,ARRAYSIZE(ConfigInfo.GlobalData.DestszIP));ConfigInfo.GlobalData.DestwPort = DestwPort;//监听个服务端口,即映射端口SOCKET localsockid = CreateSocket(INADDR_ANY, HostListenPort);if(localsockid <= 0){closesocket(localsockid);return FALSE;}while(true){//接收客户端链接AcceptSocket = accept(localsockid, NULL, NULL);if(AcceptSocket == INVALID_SOCKET)continue;//将接受到的客户请求套接字转到新的线程里处理//然后继续等待新的请求ConfigInfo.LocalData.Push(AcceptSocket);hThread = CreateThread(NULL, 0, PortTransfer_1, (LPVOID)&ConfigInfo, NULL, &dwThreadId);if(hThread)CloseHandle(hThread);else Sleep(100);}closesocket(localsockid);return true;}DWORD WINAPI PortTransfer_2(LPVOID lParam){TransferParam<ADDRESS, SOCKET> *ConfigInfo = (TransferParam<ADDRESS, SOCKET> *)lParam;SOCKET ClientSocket, ServerSocket;SOCKINFO socks;ClientSocket = ConfigInfo->LocalData.Pop();//连接到目标计算机的服务ServerSocket = ConnectHost(ConfigInfo->GlobalData.DestszIP, ConfigInfo->GlobalData.DestwPort);if(ServerSocket <= 0){printf("Error.\r\n");closesocket(ClientSocket);return 0;}socks.ClientSock = ClientSocket;//公网计算机的套接字socks.ServerSock = ServerSocket;//目标计算机服务的套接字//进入纯数据转发状态return TransmitData((LPVOID)&socks);}BOOL PortTransfer_2(char *szCtrlIP, WORD wCtrlPort, char *szIP, WORD wPort){int nRecv;int nCount=0;unsigned long lRecv;long nRet;bool fCtrlConnected=false;WORD ReqPort;HANDLE hThread;DWORD dwThreadId;SOCKET CtrlSocket;TransferParam<ADDRESS, SOCKET> ConfigInfo;_snprintf(ConfigInfo.GlobalData.DestszIP, IPADDRSIZE, "%s", szIP);ConfigInfo.GlobalData.DestwPort = wPort;while(1){while(!fCtrlConnected){printf("Creating a ctrlconnection...");//与PortTransfer_3模式(工作在公网)的计算机建立控制管道连接CtrlSocket = ConnectHost(szCtrlIP, wCtrlPort);if(CtrlSocket <= 0){printf("Failed.\r\n");Sleep(3000);}else{ConfigInfo.GlobalData.Destsock = CtrlSocket;printf("OK.\r\n");fCtrlConnected=true;}}//接收来自公网计算机的1byte命令,表示建立一个新通道nRet=ioctlsocket(CtrlSocket,FIONREAD,&lRecv);if (lRecv>0) {nRecv = recv(CtrlSocket, (char*)&ReqPort, 1, 0);fCtrlConnected=false;nCount=0;if(nRecv <= 0){closesocket(CtrlSocket);continue; //接收失败}ConfigInfo.LocalData.Push(CtrlSocket);//传递信息的结构hThread = CreateThread(NULL, 0, PortTransfer_2, (LPVOID)&ConfigInfo, NULL, &dwThreadId);if(hThread)CloseHandle(hThread);elseSleep(1000);}else{nCount++;if (nCount>=0x1000) {nCount=send(CtrlSocket,(char *)&nCount,1,0);if (nCount==SOCKET_ERROR) {printf("send error:%d\r\n",WSAGetLastError());closesocket(CtrlSocket);fCtrlConnected=false;}}}Sleep(2);}//error:printf("Error.\r\n");closesocket(CtrlSocket);return false;}DWORD WINAPI PortTransfer_3(LPVOID lParam){SOCKINFO socks;TransferParam<SOCKET, SOCKET> *ConfigInfo = (TransferParam<SOCKET, SOCKET>*)lParam;socks.ClientSock = ConfigInfo->LocalData.Pop();socks.ServerSock = ConfigInfo->GlobalData;//进入纯数据转发状态return TransmitData((LPVOID)&socks);}BOOL PortTransfer_3(WORD wCtrlPort, WORD wServerPort)//监听的两个端口{HANDLE hThread;DWORD dwThreadId;BOOL bOptVal = TRUE;bool bCtrlConnected=false;long nRet;ULONG lRecv;char *pcRecv;int bOptLen = sizeof(BOOL);TransferParam<SOCKET, SOCKET> ConfigInfo;SOCKET ctrlsockid, serversockid, CtrlSocket=0, AcceptSocket;ctrlsockid = CreateSocket(INADDR_ANY, wCtrlPort);//创建套接字if(ctrlsockid <= 0)goto error2;serversockid = CreateSocket(INADDR_ANY, wServerPort);//创建套接字if(serversockid <= 0)goto error1;while(1){while(CtrlSocket<=0){printf("Accepting new CtrlSocket...\r\n");CtrlSocket = accept(ctrlsockid, NULL, NULL);//接受来自(内网用户发起)PortTransfer_2模式建立控制管道连接的请求if(CtrlSocket == INVALID_SOCKET)CtrlSocket=0;//goto error0;//setsockopt( keep-alive......if (setsockopt(CtrlSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&bOptVal, bOptLen) == SOCKET_ERROR) {{};//CtrlSocket=0;//goto error0;//printf("Set SO_KEEPALIVE: ON\n");}//与内网用户建立了连接后就相当端口映射成功了//准备进入接收服务请求状态,并将在新起的线程中通过控制管道通知内网用户发起新的连接进行数据转发}printf("OK.\r\n");printf("Accepting new Client...\r\n");AcceptSocket = accept(serversockid, NULL, NULL);if(AcceptSocket == INVALID_SOCKET){printf("Error.\r\n");Sleep(1000);continue;}printf("OK.\r\n");nRet=ioctlsocket(CtrlSocket,FIONREAD,&lRecv);if (lRecv>0) {//若server之前发的保持连接数据则接收pcRecv=(char *)malloc(lRecv);recv(CtrlSocket,pcRecv,lRecv,0);free(pcRecv);//接收即丢弃}if (send(CtrlSocket,(char *)&nRet,1,0)==SOCKET_ERROR){closesocket(CtrlSocket);CtrlSocket = accept(ctrlsockid, NULL, NULL);setsockopt(CtrlSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&bOptVal, bOptLen);send(CtrlSocket,(char *)&nRet,1,0);}ConfigInfo.GlobalData = CtrlSocket;ConfigInfo.LocalData.Push(AcceptSocket);//把接受到的套接字Push到栈结构中,传到新起线程那边可以再Pop出来hThread = CreateThread(NULL, 0, PortTransfer_3, (LPVOID)&ConfigInfo, NULL, &dwThreadId);CtrlSocket=0;//接收一次连接后,重新置CtrlSocket为0if(hThread)CloseHandle(hThread);elseSleep(1000);}//error0:closesocket(CtrlSocket);error1:closesocket(serversockid);error2:closesocket(ctrlsockid);return false;}int main(void){WSADATA wsadata;WSAStartup(MAKEWORD(2,2),&wsadata);//模式一 本机监听端口,转发到目的IP,目的端口PortTransfer_1(123,"222.222.222.222.", 3389);//if(argc == 3)//PortTransfer_3(atoi(argv[1]), atoi(argv[2]));//else if(argc == 4)//PortTransfer_1(atoi(argv[1]), argv[2], atoi(argv[3]));//else if(argc == 5)//PortTransfer_2(argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));WSACleanup();return 0;}

0 0
原创粉丝点击