/*
端口映射

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端口命令内网机子和公网机子建立条新的数据连接,
并将请求通过新建的连接将请求转发到内网机.

Code By LZX.
2006.08.31
*/
/*
Author: LZX
E-mail: LZX@qq.com
Version: V1.1
Purpose: Mapping Port, Not support for UDP
Test PlatForm: WinXP SP2
Compiled On: VC++ 6.0
Last Modified: 2006.08.31

*/
#include <WINSOCK2.H>
#include <windows.h>
#include <stdio.h>

#pragma comment(lib, "ws2_32.lib")

#define SERVERNAME "ZXPortMap"
#define VERSION "v1.0"

#define MAXBUFSIZE 8192
#define ADDRSIZE 32

struct SOCKINFO
{
    SOCKET ClientSock;
    SOCKET ServerSock;
};
struct ADDRESS
{
    char szIP[ADDRSIZE];
    WORD wPort;
    SOCKET s;
};

A simple class of stack operator. code start.....
template<typename T>
class STACK
{
#define MAXSTACK 1024*2

private:
    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 Parameters
template<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);
}
///

int nTimes = 0;

int DataSend(SOCKET s, char *DataBuf, int DataLen)//将DataBuf中的DataLen个字节发到s去
{
    int nBytesLeft = DataLen;
    int nBytesSent = 0;
    int ret;
    //set socket to blocking mode
    int iMode = 0;
    ioctlsocket(s, FIONBIO, (u_long FAR*) &iMode);
    while(nBytesLeft > 0)
    {
        ret = send(s, DataBuf + nBytesSent, nBytesLeft, 0);
        if(ret <= 0)
            break;
        nBytesSent += ret;
        nBytesLeft -= ret;
    }
    return nBytesSent;
}

DWORD WINAPI TransmitData(LPVOID lParam)//在两个SOCKET中进行数据转发
{
    SOCKINFO socks = *((SOCKINFO*)lParam);
    SOCKET ClientSock = socks.ClientSock;
    SOCKET ServerSock = socks.ServerSock;
    char RecvBuf[MAXBUFSIZE] = {0};
    fd_set Fd_Read;
    int ret, nRecv;

while(1)
    {
        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)
            goto error;
        if(FD_ISSET(ClientSock, &Fd_Read))
        {
            nRecv = recv(ClientSock, RecvBuf, sizeof(RecvBuf), 0);
            if(nRecv <= 0)
                goto error;
            ret = DataSend(ServerSock, RecvBuf, nRecv);
            if(ret == 0 || ret != nRecv)
                goto error;
        }
        if(FD_ISSET(ServerSock, &Fd_Read))
        {
            nRecv = recv(ServerSock, RecvBuf, sizeof(RecvBuf), 0);
            if(nRecv <= 0)
                goto error;
            ret = DataSend(ClientSock, RecvBuf, nRecv);
            if(ret == 0 || ret != nRecv)
                goto error;
        }
    }

error:
    closesocket(ClientSock);
    closesocket(ServerSock);
    return 0;
}

SOCKET ConnectHost(DWORD dwIP, WORD wPort)//连接指定IP和端口
{
    SOCKET sockid;

if ((sockid = socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET)
        return 0;
    struct sockaddr_in srv_addr;
    srv_addr.sin_family = AF_INET;
    srv_addr.sin_addr.S_un.S_addr = dwIP;
    srv_addr.sin_port = htons(wPort);
    if (connect(sockid,(struct sockaddr*)&srv_addr,sizeof(struct sockaddr_in)) == SOCKET_ERROR)
        goto error;
    return sockid;
error:
    closesocket(sockid);
    return 0;
}

SOCKET ConnectHost(char *szIP, WORD wPort)
{
    return ConnectHost(inet_addr(szIP), wPort);
}

SOCKET CreateSocket(DWORD dwIP, WORD wPort)//在dwIP上绑定wPort端口
{
    SOCKET sockid;

if ((sockid = socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET)
        return 0;
    struct 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)
        goto error;
    listen(sockid,3);
    return sockid;
error:
    closesocket(sockid);
    return 0;
}

SOCKET CreateTmpSocket(WORD *wPort)//创建一个临时的套接字,指针wPort获得创建的临时端口
{
    struct sockaddr_in srv_addr = {0};
    int addrlen = sizeof(struct sockaddr_in);

SOCKET s = CreateSocket(INADDR_ANY, 0);
    if(s <= 0)
        goto error;

if(getsockname(s, (struct sockaddr*)&srv_addr, &addrlen) == SOCKET_ERROR)
        goto error;
    *wPort = ntohs(srv_addr.sin_port);
    return s;
error:
    closesocket(s);
    return 0;
}

BOOL InitSocket()
{
    WSADATA wsadata;
    return WSAStartup(MAKEWORD(2,2),&wsadata) == 0;
}

DWORD WINAPI PortTransfer_1(LPVOID lParam)
{
    TransferParam<ADDRESS, SOCKET> *ConfigInfo = (TransferParam<ADDRESS, SOCKET>*)lParam;
    SOCKET ClientSock, ServerSock;

//出栈,获得客户的套接字
    ClientSock = ConfigInfo->LocalData.Pop();
    printf("ThreadID: %d ==> Now Connecting To Server...", nTimes);
    //先连接到目标计算机的服务
    ServerSock = ConnectHost(ConfigInfo->GlobalData.szIP, ConfigInfo->GlobalData.wPort);
    if(ServerSock <= 0)
    {
        printf("Error./r/n");
        closesocket(ClientSock);
        return 0;
    }
    printf("OK./r/nStarting TransmitData/r/n");
    SOCKINFO socks;
    socks.ClientSock = ClientSock;//客户的套接字
    socks.ServerSock = ServerSock;//目标计算机服务的套接字
    //进入纯数据转发状态
    return TransmitData((LPVOID)&socks);
}

BOOL PortTransfer_1(WORD ListenPort, char *szIP, WORD wPort)
{
    HANDLE hThread;
    DWORD dwThreadId;
    SOCKET AcceptSocket;

TransferParam<ADDRESS, SOCKET> ConfigInfo;

_snprintf(ConfigInfo.GlobalData.szIP, ADDRSIZE, "%s", szIP);
    ConfigInfo.GlobalData.wPort = wPort;

//监听个服务端口,即映射端口
    SOCKET localsockid = CreateSocket(INADDR_ANY, ListenPort);
    if(localsockid <= 0)
        goto error;
    while(1)
    {
        printf("Accepting new Client...");
        AcceptSocket = accept(localsockid, NULL, NULL);
        if(AcceptSocket == INVALID_SOCKET)
            goto error;
        nTimes++;
        printf("OK./r/n");
        //将接受到的客户请求套接字转到新的线程里处理
        //然后继续等待新的请求
        ConfigInfo.LocalData.Push(AcceptSocket);
        hThread = CreateThread(NULL, 0, PortTransfer_1, (LPVOID)&ConfigInfo, NULL, &dwThreadId);
        if(hThread)
            CloseHandle(hThread);
        else
            Sleep(1000);
        
    }
error:
    printf("Error./r/n");
    closesocket(localsockid);
    return false;
}

DWORD WINAPI PortTransfer_2(LPVOID lParam)
{
    TransferParam<ADDRESS, WORD> *ConfigInfo = (TransferParam<ADDRESS, WORD> *)lParam;
    SOCKET CtrlSocket = ConfigInfo->GlobalData.s;
    DWORD dwCtrlIP;
    //WORD wPort;
    SOCKADDR_IN clientaddr;
    int addrlen = sizeof(clientaddr);
    //之前用错了个API(getsockname),这里应该用getpeername
    if(getpeername(CtrlSocket, (SOCKADDR *)&clientaddr, &addrlen) == SOCKET_ERROR)
        return 0;
    //获得运行PortTransfer_3模式的计算机的IP
    dwCtrlIP = clientaddr.sin_addr.S_un.S_addr;
    //wPort = ntohs(clientaddr.sin_port);

SOCKET ClientSocket, ServerSocket;
    SOCKINFO socks;
    printf("ThreadID: %d ==> Connecting to Client...", nTimes);
    //向公网建立新的连接
    ClientSocket = ConnectHost(dwCtrlIP, ConfigInfo->LocalData.Pop());
    if(ClientSocket <= 0)
        return 0;
    printf("OK./r/n");
    printf("ThreadID: %d ==> Connect to Server...", nTimes);
    //连接到目标计算机的服务
    ServerSocket = ConnectHost(ConfigInfo->GlobalData.szIP, ConfigInfo->GlobalData.wPort);
    if(ServerSocket <= 0)
    {
        printf("Error./r/n");
        closesocket(ClientSocket);
        return 0;
    }
    printf("OK./r/nStarting TransmitData/r/n", nTimes);
    socks.ClientSock = ClientSocket;//公网计算机的套接字
    socks.ServerSock = ServerSocket;//目标计算机服务的套接字
    //进入纯数据转发状态
    return TransmitData((LPVOID)&socks);
}

BOOL PortTransfer_2(char *szCtrlIP, WORD wCtrlPort, char *szIP, WORD wPort)
{
    int nRecv;
    WORD ReqPort;
    HANDLE hThread;
    DWORD dwThreadId;
    TransferParam<ADDRESS, WORD> ConfigInfo;
    _snprintf(ConfigInfo.GlobalData.szIP, ADDRSIZE, "%s", szIP);
    ConfigInfo.GlobalData.wPort = wPort;

printf("Creating a ctrlconnection...");
    //与PortTransfer_3模式(工作在共网)的计算机建立控制管道连接
    SOCKET CtrlSocket = ConnectHost(szCtrlIP, wCtrlPort);
    if(CtrlSocket <= 0)
        goto error;
    ConfigInfo.GlobalData.s = CtrlSocket;
    printf("OK./r/n");
    while(1)
    {
        //接收来自(工作在公网)计算机的命令,数据为一个WORD,
        //表示公网计算机监听了这个端口
        nRecv = recv(CtrlSocket, (char*)&ReqPort, sizeof(ReqPort), 0);
        if(nRecv <= 0)
            goto error;
        nTimes++;
        ConfigInfo.LocalData.Push(ReqPort);//传递信息的结构
        hThread = CreateThread(NULL, 0, PortTransfer_2, (LPVOID)&ConfigInfo, NULL, &dwThreadId);
        if(hThread)
            CloseHandle(hThread);
        else
            Sleep(1000);
    }
error:
    printf("Error./r/n");
    closesocket(CtrlSocket);
    return false;
}

DWORD WINAPI PortTransfer_3(LPVOID lParam)
{
    SOCKINFO socks;
    SOCKET ClientSocket, ServerSocket, CtrlSocket, tmpSocket;
    TransferParam<SOCKET, SOCKET> *ConfigInfo = (TransferParam<SOCKET, SOCKET>*)lParam;
    CtrlSocket = ConfigInfo->GlobalData;
    ClientSocket = ConfigInfo->LocalData.Pop();

WORD wPort;
    tmpSocket = CreateTmpSocket(&wPort);//创建个临时端口

if(tmpSocket <= 0 || wPort <= 0)
    {
        closesocket(ClientSocket);
        return 0;
    }
    //通知内网用户发起新的连接到刚创建的临时端口
    if(send(CtrlSocket, (char*)&wPort, sizeof(wPort), 0) == SOCKET_ERROR)
    {
        closesocket(ClientSocket);
        closesocket(CtrlSocket);
        return 0;
    }
    printf("ThreadID: %d ==> Waiting for server connection...", nTimes);
    ServerSocket = accept(tmpSocket, NULL, NULL);
    if(ServerSocket == INVALID_SOCKET)
    {
        printf("Error./r/n");
        closesocket(ClientSocket);
        return 0;
    }
    printf("OK./r/n");
    socks.ClientSock = ClientSocket;
    socks.ServerSock = ServerSocket;
    //进入纯数据转发状态
    return TransmitData((LPVOID)&socks);
}

BOOL PortTransfer_3(WORD wCtrlPort, WORD wServerPort)//监听的两个端口
{
    HANDLE hThread;
    DWORD dwThreadId;
    BOOL bOptVal = TRUE;
    int bOptLen = sizeof(BOOL);
    TransferParam<SOCKET, SOCKET> ConfigInfo;
    SOCKET ctrlsockid, serversockid, CtrlSocket, AcceptSocket;
    
    ctrlsockid = CreateSocket(INADDR_ANY, wCtrlPort);//创建套接字
    if(ctrlsockid <= 0)
        goto error2;
    serversockid = CreateSocket(INADDR_ANY, wServerPort);//创建套接字
    if(serversockid <= 0)
        goto error1;
    CtrlSocket = accept(ctrlsockid, NULL, NULL);//接受来自(内网用户发起)PortTransfer_2模式建立控制管道连接的请求
    if(CtrlSocket == INVALID_SOCKET)
        goto error0;
    //setsockopt( keep-alive......
    if (setsockopt(CtrlSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&bOptVal, bOptLen) == SOCKET_ERROR) {
        goto error0;
        //printf("Set SO_KEEPALIVE: ON/n");
    }
    //与内网用户建立了连接后就相当端口映射成功了
    //准备进入接收服务请求状态,并将在新起的线程中通过控制管道通知内网用户发起新的连接进行数据转发
    ConfigInfo.GlobalData = CtrlSocket;
    while(1)
    {
        printf("Accepting new Client.../r/n");
        AcceptSocket = accept(serversockid, NULL, NULL);
        if(AcceptSocket == INVALID_SOCKET)
        {
            printf("Error./r/n");
            Sleep(1000);
            continue;
        }
        nTimes++;
        printf("OK./r/n");
        ConfigInfo.LocalData.Push(AcceptSocket);//把接受到的套接字Push到栈结构中,传到新起线程那边可以再Pop出来
        hThread = CreateThread(NULL, 0, PortTransfer_3, (LPVOID)&ConfigInfo, NULL, &dwThreadId);
        if(hThread)
            CloseHandle(hThread);
        else
            Sleep(1000);
    }

error0:
    closesocket(CtrlSocket);
error1:
    closesocket(serversockid);
error2:
    closesocket(ctrlsockid);
    return false;
}

void Usage(char *ProName)
{
    printf (SERVERNAME" "VERSION" " "By LZX./r/n");
    printf ("Usage:/r/n"
            " %s ctrlPort ServerPort/r/n"
            " %s Port Dest_IP Port/r/n"
            " %s ctrlIP ctrlPort Dest_IP Port/r/n", ProName, ProName, ProName);
}

int main(int argc, char **argv)
{

if(! InitSocket())
        return 0;
    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]));
    else
        Usage(argv[0]);

WSACleanup();
    return 0;
}

端口映射vc++6.0编译【转】相关推荐

  1. [强]用VC++6.0编译调试汇编程序

    用VC++6.0编译调试汇编程序     使用汇编的一点心得,还不完善,希望高手指点. 第一步:新建工程     新建空的Win32控制台程序. 第二步:添加文件     把源程序和资源文件添加进新建 ...

  2. VC++6.0编译环境介绍(转)

    大家可能一直在用VC开发软件,但是对于这个编译器却未必很了解.原因是多方面的.大多数情况下,我们只停留在"使用"它,而不会想去"了解"它.因为它只是一个工具,我 ...

  3. windows xp vc 6.0编译最新net-snmp源码

    net-snmp作为开源的snmp协议,是一款snmp协议开发的利器,比较好用,具有跨平台,可定制等特点,但编译很蛋疼,折腾了两天,下面把最简单过程写在下面. 一.安装Microsoft Platfo ...

  4. vc 6.0常见编译错误及改正方法

    最常见VC++6.0编译错误信息集合 1.fatal error C1010: unexpected end of file while looking for precompiled header ...

  5. VC++6.0安装、编译NTL类库

    前言 为了解决大数运算的问题,世界各国的软件开发人员和研究学者都进行了很多 的研究和实践.近年来,越来越多的开发人员开始重视软件工程的作用,为了减少 重复劳动,提高软件的质量和代码复用,许多优秀的大数 ...

  6. VC++ 6.0的小花招

    Visual Studio系列中产品中,Visual Studio 6.0是最经典的一个版本,虽然后来有Visual Studio .NET 2003,以及2005,也确实添加了很多让我觉得激动的特性 ...

  7. 华三防火墙配置端口地址转换_H3C SecPath 防火墙设置之端口映射(命令)

    登陆系统后: 1.显示防火墙当前生效配置参数. display current-configuration 找到如下信息: # interface Ethernet0/0 ip address 172 ...

  8. docker如何查看宿主机到容器端口映射

    docker/Docker如何查看宿主机到容器端口映射关系 背景 前些天的时候, 在定位问题时发现docker emqx 连接websocket (8083)端口出现异常. 经过很长时间定位, 才发现 ...

  9. 端口映射软件大-比较|内网端口映射器使用方法

    [转载]端口映射软件大-比较|内网端口映射器使用方法 2010-05-15 13:34 功能多少作为顺序: PortTunnel 2.0.13 简体中文版 优点:功能最为强大,默认为服务模式. 缺点: ...

  10. Docker 端口映射

    在启动容器时,如果不配置宿主机器与虚拟机的端口映射,外部程序是无法访问虚拟机的,因为没有端口. 实现外界和Docker容器进行通讯,要么做link要么做Port映射 端口映射: docker指令:do ...

最新文章

  1. python使用正则表达式验证邮箱地址语法有效性
  2. 第十六周项目一-小玩文件(1)
  3. 单链表建立(头插法,头插法,用数组),求长,插入,删除,输出,释放(递归释放和循环释放),归并(递增和递减)
  4. windows2003 服务器安全配置的建议
  5. android音频系统之AudioTrack的使用
  6. 使用Lambda 表达式注册Bean
  7. mac终端连接linux中断,Mac电脑iTerm2链接Linux服务器断线解决方案
  8. Epic:把虚幻引擎推向所有游戏平台
  9. 计算机应用有那些技校好,技校都有哪些专业? 就业前景好的有哪些
  10. Java中System.nanoTime()的使用
  11. Git的下载与安装(详细)
  12. k近邻算法_机器学习算法之——K最近邻(k-Nearest Neighbor,KNN)分类算法原理讲解...
  13. ssm房屋中介管理系统毕业设计(附源码、运行环境)
  14. 三款适合HDMI信号分配的分配器芯片
  15. template < class T> ,map和vector用法——恶补c++
  16. Android系统应用
  17. 和尚吃馒头c语言程序,(八十一)约瑟夫环/鲁智深吃馒头
  18. PHP在线发邮件 无需服务端软件
  19. android找不到 windows 7 共享无线网络连接,Windows 7下wifi共享上网设置教程 没有无线路由器也能用wifi...
  20. 编程之旅第一章之初识C语言(1)

热门文章

  1. 什么是CSR以及CSR的作用和生成方法
  2. C++学习(complex类)
  3. Java程序员怎么规划五年职业生涯
  4. 从前端到全栈-基础能力-js-异步编程
  5. 【Bug修复】java.lang.IllegalArgumentException、java.lang.NullPointerException 问题解决修复
  6. 迅雷下载边下边播设置为本地安装的浏览器
  7. 松柏先生:参透五百年不遇的《求贤令》,何愁品牌不立!
  8. Bugku MISC 再也没有纯白的灵魂
  9. Unity新创建的物体是灰色的,而且无法通过白色材质球给予纯白色(结果还是灰色)
  10. uWSGI +Flask+torch Cannot re-initialize CUDA in forked subprocess