Linux C/C++实现Socks5代理及Socks5协议抓包分析

如果你想在保持匿名的同时以更好的安全性和性能浏览网页,SOCKS5代理是一个不错的选择。
在使用互联网时,存在许多安全和数据隐私风险。此外,您可能不得不面对一些限制。想象一下,你想访问一个网站,但你根本无法访问它,原因可能是地理限制。但是,如果你决定访问该网站怎么办?使用像SOCKS5代理这样的代理服务器可以增加安全性和隐私性。

什么是代理?

代理或代理服务器是充当用户和网络之间的中介或网关的服务器应用程序。因此,当您在计算机上启用代理的情况下在网络上搜索某个内容时,此请求会首先到达代理服务器。此服务器将评估请求,然后代表您向目标网页发出请求。一旦网页批准了请求并发送了请求的信息,它将首先到达代理服务器,然后作为用户到达您。

这意味着你的请求不会直接进入你试图访问的网页。相反,代理服务器会为您这样做,以便您的身份(如IP地址)保持隐藏。因此,目标网站无法识别或阻止您的实际IP地址,您将可以访问整个网站。通过这种方式,您可以从任何地方访问任何网站,并在访问时保护您的安全和隐私。

代理与VPN是否相同

许多人将代理与VPN混淆,认为它们是一样的。但事实并非如此。不过,它们看起来可能很相似,因为它们都用于隐藏请求网页获取信息的用户的身份。它们都通过外部服务器路由请求和响应,同时提供隐私和安全。因此,您可以在保持匿名的同时访问任何您想要的内容。

然而,存在特定的差异,因此理解代理与VPN是至关重要的。VPN对您的连接进行加密,从而提供更好的安全保护,免受黑客攻击。但代理并不能做到这一点,尽管它们提供了一定程度的安全性。

此外,还有不同类型的代理,如前向代理、透明代理、匿名代理、旋转代理、扭曲代理、数据中心代理、住宅代理、反向代理、公共代理、私有代理、Socks代理等。

让我们详细讨论一下SOCKS5。

什么是SOCKS5代理?

套接字安全(SOCKS)是一种类似HTTP/S、TCP等的网络协议,用于促进服务器之间的连接。它使用代理服务器在请求信息的用户和目标服务器之间路由数据包。这种类型的代理服务器是SOCKS代理服务器,可以路由任何程序或协议创建的任何类型的流量。

SOCKS有两个版本——SOCKS5和SOCKS4。SOCKS5支持不同的身份验证方法和UDP代理,而SOCKS4则不支持。

SOCKS5代理更安全,因为它们提供完整的TCP连接并使用SSH协议和身份验证机制。因此,传输中的每个数据包都经过验证,只有安全的数据包才能通过,从而增强安全性和隐私性。

为什么要使用SOCKS5代理服务器?

以下是使用SOCKS5对个人和企业都有益的原因:

  • 更好的性能

与其他代理不同,SOCKS5不重写数据包。相反,它在系统之间中继网络流量。因此,它涉及更少的错误并导致更好的性能。

  • 更高的安全性

它提供了比其他代理更好的安全性,因为它支持各种身份验证方法来验证身份。

  • 隐私

除了安全之外,在使用网络时最好隐藏您的个人信息或设备身份以保持匿名。

Socks5协议分析

如图这里是最简单的一个socks连接代理的过程,采用的是无用户密码认证的socks代理。我们这里忽略掉tcp三次握手和四次挥手的过程,只分析socks协议。

  • 客户端 -> 代理服务器,请求认证

以 05 01 00 为例:
Version: 5 #05,socks协议版本号
Authentication Method Count: 1 #01,客户端提供了一种认证方法
Method[0]: 0 (No authentication) #00对应的方法字段,无需身份验证

V5身份验证方法:

#define NO_AUTHENTICATION           0
#define GSS_API_AUTHENTICATION      1
#define USER_NAME_AUTHENTICATION    2
#define CHAP_AUTHENTICATION         3
#define AUTHENTICATION_FAILED       0xff

  • 代理服务器 -> 客户端,响应认证

这里服务端的响应只有两个字节,版本号和确认认证的方法,0x00,则无需客户端发送进一步认证的信息。

由于我代码中设置的是无需用户密码认证,所以这里响应为 05 00 。

  • 客户端 -> 代理服务器,发送目标信息

Socks命令:

#define CONNECT_COMMAND         1
#define BIND_COMMAND            2
#define UDP_ASSOCIATE_COMMAND   3
#define PING_COMMAND            0x80
#define TRACERT_COMMAND         0x81
  • 代理服务器 -> 客户端,确认连接

    在代理服务器确认回应为 0x00 时,此次 SOCKS5 协议协商部分顺利完成,然后就是数据传输阶段。

Linux C/C++实现Socks5代理

bool method_exists(struct method_request * method_req, uint8_t method);
void get_uname_passwd(struct auth_request * req, uint8_t * ulen, uint8_t ** uname, uint8_t * plen, uint8_t ** passwd);
in_addr_t get_dst_addr(union dst_or_bnd * dst, uint8_t atyp);
in_port_t get_dst_port(union dst_or_bnd * dst, uint8_t atyp);
uint8_t * get_payload(struct datagram * dgram, int buflen, int * len);
void udp_relay_cb(struct event_data * fd_data);
void tcp_relay_cb(struct event_data * fd_data);
void request_cb(struct event_data * fd_data);
void auth_cb(struct event_data * fd_data);
void handshake_cb(struct event_data * fd_data);
void accept_cb(struct event_data * fd_data);
bool load_users(const char * path);

int main(int argc, char * argv[])
{
...

    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) 
    {
        error("signal");
        exit(EXIT_FAILURE);
    }

    bool daemon = false;
    in_addr_t addr = htonl(DEFAULT_ADDR);
    in_port_t port = htons(DEFAULT_PORT);

...
    for (;;) 
    {
        opt = getopt(argc, argv, ":a:p:u:dhv");
        if (opt == -1) break;
        switch (opt) {
            case 'a':
                addr = inet_addr(optarg);
                break;
            case 'p':
                port = htons(atoi(optarg));
                break;
            case 'u':
                if (!load_users(optarg)) exit(EXIT_FAILURE);
                method = USERNAME_PASSWORD;
                after_handshake = auth_cb;
                break;
            case 'd':
                daemon = true;
                break;
            case 'h':
                usage(argv[0]);
                exit(EXIT_SUCCESS);
            case 'v':
                verbose = true;
                break;
            case ':':
                printf("Missing argument after: -%c\n", optopt);
                usage(argv[0]);
                exit(EXIT_FAILURE);
            case '?':
                printf("Invalid argument: -%c\n", optopt);
                usage(argv[0]);
                exit(EXIT_FAILURE);
        }
    }

    if (method == USERNAME_PASSWORD) 
    {
        puts("USERNAME/PASSWORD");
        printf("%d users\n", nusers);
    } else 
    {
        puts("NO AUTHENTICATION REQUIRED");
    }

    int fd = create_and_listen(addr, port);
    if (!fd) exit(EXIT_FAILURE);
    printf("Listening on %s:%hu\n", inet_ntoaddr(&addr), ntohs(port));

    if (daemon) 
    {
        pid_t pid = fork();
        if (pid == -1) 
        {
            perror("fork");
            exit(EXIT_FAILURE);
        }
        if (pid > 0) 
        {
            printf("PID is %d\n", pid);
            exit(EXIT_SUCCESS);
        }
    }

...
}

If you need the complete source code, please add the WeChat number (c17865354792)

选项 -a 和 -p 分别用来指定服务器绑定的 IP 地址和端口号。

选项 -u 用于开启用户名密码认证方式,选项后面必须跟上一个文件的路径。该文件的每一行对应一个用户,用户名和密码之间用逗号 , 隔开,例如:

代码运行代码后需要在Chrome 、Firefox 浏览器设置: socks 主机填写 127.0.0.1, 端口填写: 1080, 选择 SOCKS v5 代理.

使用 curl 测试:

curl --socks5 127.0.0.1:1080 https://www.baidu.com

总结

代理被认为是确保您的在线活动保持隐私的最佳方式之一。现在有很多代理类型,有些是基本的,有些是高级的。但是,要在SOCKS5和HTTP代理之间做出选择,需要深入了解每种类型的工作方式以及它们传达的配置。只有这样,才能为您的特定用例选择最佳选项。

Welcome to follow WeChat official account【程序猿编码

参考:https://www.rfc-editor.org/rfc/pdfrfc/rfc1929.txt.pdf
https://www.rfc-editor.org/rfc/pdfrfc/rfc1928.txt.pdf

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是C++实现socks5端口转发的代码示例: ```cpp #include <iostream> #include <string> #include <thread> #include <vector> #include <boost/asio.hpp> using boost::asio::ip::tcp; class Session : public std::enable_shared_from_this<Session> { public: Session(tcp::socket socket) : socket_(std::move(socket)) {} void start() { do_read(); } private: void do_read() { auto self(shared_from_this()); socket_.async_read_some(boost::asio::buffer(data_, max_length), [this, self](boost::system::error_code ec, std::size_t length) { if (!ec) { do_write(length); } }); } void do_write(std::size_t length) { auto self(shared_from_this()); boost::asio::async_write(socket_, boost::asio::buffer(data_, length), [this, self](boost::system::error_code ec, std::size_t /*length*/) { if (!ec) { do_read(); } }); } tcp::socket socket_; enum { max_length = 1024 }; char data_[max_length]; }; class Server { public: Server(boost::asio::io_context& io_context, short port) : acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) { do_accept(); } private: void do_accept() { acceptor_.async_accept( [this](boost::system::error_code ec, tcp::socket socket) { if (!ec) { std::make_shared<Session>(std::move(socket))->start(); } do_accept(); }); } tcp::acceptor acceptor_; }; int main(int argc, char* argv[]) { try { if (argc != 2) { std::cerr << "Usage: socks5_server <port>\n"; return 1; } boost::asio::io_context io_context; Server s(io_context, std::atoi(argv[1])); std::vector<std::thread> threads; for (std::size_t i = 0; i < std::thread::hardware_concurrency(); ++i) { threads.emplace_back([&io_context]() { io_context.run(); }); } for (auto& t : threads) { t.join(); } } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; } ``` 以上代码实现了一个简单的socks5服务器,可以监听指定端口并接受来自客户端的连接请求。在接受到连接请求后,服务器会创建一个新的Session对象来处理该连接。Session对象会异步读取客户端发送的数据,并将其原封不动地发送回去。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值