在我做的项目中,经常遇到一种如下形式的网络结构。

出于安全的考虑,server处于防火墙之后,client无法直接访问,只能通过telnet登陆到proxy server上访问。在这种方式下,就无法利用cient上的各种强大的桌面工具(如数据库客户端等),只能通过telnet的命令行形式交互,确实有些不便。

我们可以通过端口映射解决这个问题,实现client到server的"直接访问"。当client想访问server时,只需要与proxy的某个端口建立连接,proxy监听到这个连接后,建立一个与server的连接(client的目标),同时提供这两个连接的消息传输管道。这样,所有client发到proxy的消息都发送到了server上,server的消息也发送到了proxy上,从而实现了client到server的访问。

由于连接的数目可能较多,并且proxy程序起着一个消息中转的作用,因此程序本身需要较高的socket通信效率,所有的操作都不能阻塞,否则严重影响其它的进程通信,因此程序中的socket的连接,通信方式都必须采用异步操作。(多线程的方式如果连接的进程较多时则开销太大)。

这种方式十分简单有效,并且不需要对客户端和服务器端做任何修改。不足的地方有如下几处:

  1. proxy需要中转所有的消息,负荷较大。(不过处理目前的几十个客户端应用是绰绰有余,并且目前的通信瓶颈一般在internet上)
  2. 需要在proxy上建立端口监听,并且所监听的端口需要能被client直接访问,这种情况的网络很多时候得不到满足。(大多时候proxy只开放了几个有限的端口,并无多余的端口让端口映射程序绑定)

本来我用C#写了一个,程序非常简单,这里就不拿出来了。

后来由于要把这个程序放到Unix服务器上长期运行,我就用C++重写了一下,最初我是用socket api写的,可程序的可读性总是不尽人意,后来就改用了asio库(asio 0.3.8 rc3,与早期的asio库不兼容),通过boost的asio,function,smart_ptr这几个库的运用,一个C++版的端口映射程序便诞生了,精简、高效、安全、跨平台,原来c++下的异步socket也可以如此优雅。^_^

代码如下:

#include <list>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;
using namespace std;

class socket_client
    : public boost::enable_shared_from_this<socket_client>
    ,public tcp::socket
{
public:
    typedef boost::shared_ptr<socket_client> pointer;

static pointer create(boost::asio::io_service& io_service)
    {
        return pointer(new socket_client(io_service));
    }

public:
    socket_client(boost::asio::io_service& io_service)
        :tcp::socket(io_service)
    {
    }
};

class socket_pipe
{
public:
    socket_pipe(socket_client::pointer read,socket_client::pointer write)
        :read_socket_(*read),write_socket_(*write)
    {
        read_ = read;
        write_ = write;
        begin_read();
    }

private:
    void begin_read()
    {
        read_socket_.async_read_some(boost::asio::buffer(data_, max_length),
            boost::bind(&socket_pipe::end_read, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }

void end_read(const boost::system::error_code& error, size_t bytes_transferred)
    {
        if(error)
            handle_error(error);
        else
            begin_write(bytes_transferred);
    }

void begin_write(int bytes_transferred)
    {
        boost::asio::async_write(write_socket_,
            boost::asio::buffer(data_, bytes_transferred),
            boost::bind(&socket_pipe::end_write, this,
            boost::asio::placeholders::error));
    }

void end_write(const boost::system::error_code& error)
    {
        if(error)
            handle_error(error);
        else
            begin_read();
    }

void handle_error(const boost::system::error_code& error)
    {
        read_socket_.close();
        write_socket_.close();

delete this;
    }

private:
    socket_client& read_socket_;
    socket_client& write_socket_;

socket_client::pointer read_;
    socket_client::pointer write_;

enum { max_length = 1024 };
    char data_[max_length];
};

class async_listener
{
public:
    typedef boost::function<void (socket_client::pointer client)> accept_handler;
    typedef boost::shared_ptr<async_listener> pointer;

public:
    async_listener(short port,boost::asio::io_service& io_service)
        :io_service_(io_service),
        acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
    {
        begin_accept();
    }

void begin_accept()
    {
        socket_client::pointer client = socket_client::create(io_service_);
        acceptor_.async_accept(*client,
            boost::bind(&async_listener::end_accept, this, client,
            boost::asio::placeholders::error));
    }

void end_accept(socket_client::pointer client, const boost::system::error_code& error)
    {
        if(error)
            handle_error(error);

begin_accept();

if(!handle_accept.empty())
            handle_accept(client);
    }

void handle_error(const boost::system::error_code& error)
    {
    }

public:
    accept_handler handle_accept;

private:
    tcp::acceptor acceptor_;
    boost::asio::io_service& io_service_;
};

class port_map_server
{
public:
    port_map_server(boost::asio::io_service& io_service)
        :io_service_(io_service)
    {
    }

void add_portmap(short port,tcp::endpoint& remote_endpoint)
    {
        async_listener::pointer listener(new async_listener(port,io_service_));
        listeners.push_back(listener);

listener->handle_accept = boost::bind(&port_map_server::handle_accept
            ,this,remote_endpoint,_1);
    }

void handle_accept(tcp::endpoint remote_endpoint,socket_client::pointer client)
    {
        begin_connect(remote_endpoint,client);
    }

void begin_connect(tcp::endpoint& remote_endpoint,socket_client::pointer socket_local)
    {
        socket_client::pointer socket_remote = socket_client::create(io_service_);
        socket_remote->async_connect(remote_endpoint,
            boost::bind(&port_map_server::end_connect, this,
            boost::asio::placeholders::error,socket_local,socket_remote));
    }

void end_connect(const boost::system::error_code& error,socket_client::pointer socket_local,socket_client::pointer socket_remote)
    {
        if(error)
        {
            handle_error(error);
        }
        else
        {
            new socket_pipe(socket_local,socket_remote);
            new socket_pipe(socket_remote,socket_local);
        }
    }

void handle_error(const boost::system::error_code& error)
    {
    }

private:
    boost::asio::io_service& io_service_;
    list<async_listener::pointer> listeners;
};

int main()
{
    try
    {
        boost::asio::io_service io_service;

tcp::endpoint ep(boost::asio::ip::address_v4::from_string("192.168.1.193"),23);
        tcp::endpoint ep2(boost::asio::ip::address_v4::from_string("192.168.1.175"),23);
        
        port_map_server server(io_service);

server.add_portmap(3000,ep);
        server.add_portmap(4000,ep2);
        io_service.run();
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }

return 0;
}

转载于:https://www.cnblogs.com/TianFang/archive/2007/08/10/850901.html

通过端口映射突破防火墙相关推荐

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

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

  2. 利用socket转发和反弹端口技术突破防火墙进入内

    TCP端口反弹技术 反弹技术,该技术解决了传统的远程控制软件不能访问装有防火墙和控制局域网内部的远程计算机的难题.反弹端口型软件的原理是,客户端首先登录到FTP服务器,编辑在***软件中预先设置的主页 ...

  3. linux设置mysql防火墙端口映射_Linux防火墙默认是关闭3306端口,iptables实现端口转发、端口映射及双向通路...

    iptables实现端口转发.端口映射及双向通路其实不难配置,看下文: 允许数据包转发: #echo 1 > /proc/sys/net/ipv4/ip_forward 转发TCP 8081到x ...

  4. linux 防火墙 443端口映射,linux防火墙实现端口转发、端口映射及双向通路

    iptables实现端口转发.端口映射及双向通路其实不难配置,看下文: 允许数据包转发: #echo 1 > /proc/sys/net/ipv4/ip_forward 转发TCP 8081到x ...

  5. 华为路由器 端口映射与防火墙

    场景 一般企业网络由于缺少IP地址,所以很多内部的对外服务需要路由器上面做NAT进行映射.但是映射也会遇到一些安全问题,需要部署相应的filter进行过滤和防护. 解决方案 华为路由器信息 Huawe ...

  6. linux7防火墙端口映射,使用centos7防火墙firewall实现端口映射,实现远程内网3389桌面...

    本是为了解决linux远程连接windows桌面的问题.转来转去,搞成了端口映射和防火墙.我也不想麻烦啊.尝试了网上说的各种,rdesktop和FreeRDP(FreeRDP是开源的远程桌面系统),都 ...

  7. HUAWEI防火墙端口映射配置

    拓扑: 这里把zabbix的80端口映射到防火墙的192.168.64.3的6060端口 NAT配置 转换成命令行就是 nat server tozabbix protocol tcp global ...

  8. 配置方法_CISCO防火墙端口映射配置方法

    今天朗联来为大家分享CISCO防火墙端口映射配置方法,首先先简单介绍一下什么是防火墙,Cisco防火墙是网络间的墙,主要为防止非法侵入,过滤信息等,从结构上讲,简单地说是一种PC式的电脑主机加上闪存( ...

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

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

最新文章

  1. OpenYurt 深度解读:如何构建 Kubernetes 原生云边高效协同网络?
  2. [置顶]       设计模式之六大原则——单一职责原则(SRP)
  3. 大学生应当趁早谋划未来(二)--给表弟的建议
  4. java容易掉发吗_容易被忽略的面试题—Java高并发
  5. 1365. 有多少小于当前数字的数字
  6. acer清理工具 clear下载_免流量工具聚合下载,包含全部工具
  7. VsDoc for jQuery
  8. 自己写个简易版 PicGo
  9. android6变化,一次尝鲜体验 关于一加6升级Android P后的变化
  10. android图片选择库selectp,浅谈android的selector背景选择器
  11. StarRocks不稳定版本(解除AVX2指令集限制)
  12. RadarNet: Efficient Gesture Recognition Technique Utilizing a Miniaturized Radar Sensor
  13. UESTC-1633 去年春恨却来时,落花人独立,微雨燕双飞(取模最短路)
  14. 候选键的计算(数据库系统概论)
  15. 古剑奇谭3steam服务器稳定吗,国产游戏《古剑奇谭3》占据steam热销榜第一?这么好玩吗?...
  16. VMware虚拟网络编辑器,没有桥接模式或本地计算机不显示网络适配器
  17. 不安装DBC2000安装架设传奇服务端的方法
  18. Rust 用于 STM32 开发
  19. 手机方案厂商怨高通门槛高 联发科影响力犹存
  20. 【Python】利用tkinter开发测手速小游戏

热门文章

  1. 性能比拼!超详细的Tengine GEMM矩阵乘法汇编教程
  2. 13篇京东CVPR 2019论文!你值得一读~
  3. linux 火狐无法执行二进制文件_Linux无法执行二进制文件
  4. Python 超简单一键美化你的文章
  5. python 基础 - 循环语句
  6. 次世代游戏设计的相关介绍
  7. linux监控mysql性能,MySQL 性能监控4大指标——第二部分
  8. C++ 20发布后,这个老牌编程语言又“真香”了
  9. 深度学习论文阅读进阶路径图
  10. 谈谈Tensorflow的Batch Normalization