Linux C/C++实现SSL的应用层VPN (MiniVPN)

这篇具有很好参考价值的文章主要介绍了Linux C/C++实现SSL的应用层VPN (MiniVPN)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

SSL协议和VPN(虚拟私人网络)原理是网络安全领域中的两个重要概念。

SSL协议,全称安全套接层(Secure Sockets Layer),是一种广泛应用于互联网的安全协议,主要在两个通信端点之间建立安全连接,以保护数据的传输安全。具体来说,SSL通过使用公钥加密算法实现数据的加密和解密,在客户端和服务器之间建立安全的通信通道。它还使用数字证书来验证通信双方的的身份,一旦身份验证成功,SSL就会使用加密算法对通信数据进行加密,确保数据在传输过程中不被篡改或窃取。

VPN是一种可以在公共网络上建立加密通道的技术,通过这种技术可以使远程用户访问公司内部网络资源时,实现安全的连接和数据传输。VPN通常是通过虚拟专用网络(Virtual Private Network)来实现的,即在公共网络上建立一个虚拟的专用网络,将用户的数据流量加密并隧道化,使得数据在传输过程中无法被窃听和篡改。

总的来说,SSL协议和VPN原理都是为了实现网络安全而设计的。SSL协议主要保护数据的传输安全,而VPN技术则是在公共网络上建立加密通道,使得数据在传输过程中更加安全。

OpenSSL库用于实现SSL的应用层VPN

OpenSSL是一个功能强大的开源SSL库,它提供了丰富的API和工具,可以用于实现SSL/TLS协议、加密算法、证书处理等功能。它还包含了IPSec和L2TP等VPN协议的实现。

使用OpenSSL库实现SSL的应用层VPN需要用到以下一些函数:

SSL_CTX_new(const SSL_METHOD *method):创建新的SSL上下文结构体。
SSL_new(SSL_CTX *ctx):基于SSL上下文创建一个新的SSL结构体。
SSL_set_fd(SSL *ssl, int fd):将SSL结构体的文件描述符设置为传入的文件描述符。
SSL_set_connect_state(SSL *ssl):设置SSL结构体为客户端模式。
SSL_do_handshake(SSL *ssl):执行SSL握手过程,与对方建立安全的连接。
SSL_write(SSL *ssl, const void *buf, int len):向对方发送数据。
SSL_read(SSL *ssl, void *buf, int len):从对方接收数据。
SSL_shutdown(SSL *ssl):关闭SSL连接,发送关闭通知并终止会话。
SSL_free(SSL *ssl):释放SSL结构体及其相关资源。
SSL_CTX_free(SSL_CTX *ctx):释放SSL上下文及其相关资源。

这些是OpenSSL库中一些常用的函数,它们用于在C语言中实现SSL的应用层VPN。在实际开发中,你可能还需要查看OpenSSL的文档和示例代码以获得更详细的信息和指导。

证书颁发机构

证书颁发机构是SSL协议中非常重要的一个环节,它负责为服务器颁发数字证书,以验证服务器的身份。客户端在和服务器建立连接时,会验证服务器的身份,以确保连接的安全性。

密钥交换

SSL协议使用密钥交换协议来协商客户端和服务器之间的加密密钥。密钥交换协议包括RSA密钥交换、Diffie-Hellman密钥交换等,它们都可以用于在客户端和服务器之间建立一个安全的通信通道。

Linux C/C++实现SSL的应用层VPN(实现MiniVPN)

  • vpn_client:

要使用OpenSSL命令生成CA证书(ca.crt)、客户端证书(client.crt)、客户端密钥(client.key)以及客户端的证书请求(client.crs),可以按照以下步骤进行操作:
生成CA证书(ca.crt):

openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 365 -key ca.key -sha256 -out ca.crt

上述命令将生成一个2048位的RSA私钥(ca.key)并使用它创建一个自签名的CA证书(ca.crt)。
生成客户端证书(client.crt)和客户端密钥(client.key):

openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr

上述命令将生成一个2048位的RSA私钥(client.key)并使用它创建一个证书请求(client.csr)。
生成客户端证书请求的证书(client.crs):

openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt

上述命令将使用CA证书(ca.crt)和CA私钥(ca.key)对客户端证书请求(client.csr)进行签名,生成客户端证书(client.crt)。
完成以上步骤后,你将得到以下文件:
ca.crt:CA证书
client.crt:客户端证书
client.key:客户端密钥
client.crs:客户端证书请求(通常不需要使用,但可以保留作为记录)

int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx);
SSL *setupTLSClient(const char *hostname);
int setupTCPClient(const char *hostname, int port);
int createTunDevice();
int try_login(SSL *ssl);
void sendto_TUN(SSL *ssl, int tunfd);
void sendto_SSL(SSL *ssl, int tunfd);
...
#define CERTF HOME "client.crt"
#define KEYF HOME "client.key"
#define CACERT HOME "ca.crt"
...
int main(int argc, char *argv[])
{
...

    /*------ Destination initialization ------*/
    printf(PREFIX "Enter server name:");
    scanf("%s", hostname);
    printf(PREFIX "Enter port:");
    scanf("%d", &port);
    /*------ TLS initialization ------*/
    SSL *ssl = setupTLSClient(hostname);
    /*------ TCP connection ------*/
    int sockfd = setupTCPClient(hostname, port);
    /*------ TLS handshake ------*/
    SSL_set_fd(ssl, sockfd);
    int err = SSL_connect(ssl);
    CHK_SSL(err);
    printf(PREFIX "SSL connected! \n");
    printf(PREFIX "SSL connection using %s\n", SSL_get_cipher(ssl));
    /*------ Authenticating ------*/
    int ret = try_login(ssl);
    //login failed
    if (ret < 0){
        printf(PREFIX"Login failed!\n");
        SSL_shutdown(ssl);
        SSL_free(ssl);
        close(sockfd);
        return 0;
    }
    printf(PREFIX "Login successfully!\n");
    /*------ Allocate IP ------*/
    char client_IP[64] = {0};
    char cmd[100];
    SSL_read(ssl, client_IP, sizeof(client_IP));
    printf(PREFIX "Auto-assigned IP:%s\n", client_IP);
    /*------ Add route ------*/
    int tunfd = createTunDevice();
    sprintf(cmd, "sudo ifconfig tun0 %s/24 up", client_IP);
    system(cmd);
    sprintf(cmd, "sudo route add -net 192.168.60.0/24 tun0");
    system(cmd);
    /*------ Listen sock&tun0 ------*/
    while (1)
    {
        fd_set readFDSet;
        int ret;
        FD_ZERO(&readFDSet);
        FD_SET(sockfd, &readFDSet);
        FD_SET(tunfd, &readFDSet);
        ret = select((sockfd > tunfd ? sockfd : tunfd) + 1, &readFDSet, NULL, NULL, NULL);
        if (FD_ISSET(sockfd, &readFDSet))
        {
            ret = sendto_TUN(ssl, tunfd);
            // 服务端关闭会话
            if (ret == -1)
            {
                printf(PREFIX "Server disconnected!\n");
                SSL_shutdown(ssl);
                SSL_free(ssl);
                close(sockfd);
            }
        }
        ...
        if (FD_ISSET(tunfd, &readFDSet))
            sendto_SSL(ssl, tunfd);
    }
    return 0;
}
  • vpn_server:

您可以使用以下步骤生成CA证书(ca.crt)、服务器证书(server.crt)、服务器密钥(server.key)以及服务器证书请求(server.crs)文件:
生成CA证书(ca.crt):

openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 365 -key ca.key -sha256 -out ca.crt

这将生成一个2048位的RSA私钥(ca.key),然后使用它创建自签名的CA证书(ca.crt)。
生成服务器证书(server.crt)和服务器密钥(server.key):

openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr

这将生成一个2048位的RSA私钥(server.key),然后使用它创建一个证书请求(server.csr)。
生成服务器证书请求的证书(server.crt):

openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt

这将使用CA证书(ca.crt)和CA私钥(ca.key)对服务器证书请求(server.csr)进行签名,生成服务器证书(server.crt)。
完成以上步骤后,您将得到以下文件:
ca.crt:CA证书
server.crt:服务器证书
server.key:服务器密钥
server.crs:服务器证书请求(通常不需要使用,但可以保留作为记录)

...
typedef struct
{
    char client_ip[16];
    char virtual_ip[16];
    int socket_fd;
    SSL *ssl_session;
} session_t;

typedef struct
{
    int last_byte_IP;
    bool if_valid;
} last_byte_pool;
void initialize_IP_POOL();
int add_session(const char *client_ip, const char *virtual_ip, int socket_fd,SSL* ssl_session);
session_t *find_session(const char *virtual_ip);
void remove_session(int client_sock);
SSL *setupTLSServer();
int setupTCPServer();
int createTunDevice();
int sendto_TUN(SSL *ssl, int client_sock, int tunfd);
void sendto_SSL(int tunfd);
int login(char *user, char *passwd);
int verify_user(SSL *ssl, struct sockaddr_in client_addr, int sock);
...
#define CERTF HOME "server.crt"
#define KEYF HOME "server.key"
#define CACERT HOME "ca.crt"
...
int main(int argc, char **argv)
{
...
    /*------ TCP Connect ------*/
    int listen_sock = setupTCPServer();
    if (listen_sock <= 0)
        printf(PREFIX "Create listen_sock failed\n");
    /*------ tunnel init, redirect and forward ------*/
    int tunfd = createTunDevice();
    system("sudo ifconfig tun0 192.168.53.1/24 up");
    system("sudo sysctl net.ipv4.ip_forward=1");
    /*------ Initialize IP pool ------*/
    initialize_IP_POOL();
    /*------ Manage multiple tunnels ------*/
    while (1)
    {
...
        for (i = 0; i < MAX_SESSIONS; i++)
        {
            // 将大于0的项加入readfds
            if (session_table[i].socket_fd > 0)
            {
                FD_SET(session_table[i].socket_fd, &readfds);
                if (session_table[i].socket_fd > max_fd)
                    max_fd = session_table[i].socket_fd;
            }
        }
        int ret = select(max_fd + 1, &readfds, NULL, NULL, NULL);
        if (ret <= 0)
            printf(PREFIX "Select fds failed\n");
        // 当有新的客户端连接请求
        if (FD_ISSET(listen_sock, &readfds))
        {
            int new_sock = accept(listen_sock, (struct sockaddr *)&sa_client, &client_len);
            CHK_ERR(new_sock, "accept");
            printf(PREFIX "TCP accept successfully! sock:%d\n", new_sock);
            // 连接的客户端数量达到上限
            if (session_count >= MAX_SESSIONS)
            {
                printf(PREFIX "Client connection full!\n");
                close(new_sock);
                continue;
            }
            //为该会话创建一个新的ssl
            SSL *ssl = setupTLSServer();
            ret = SSL_set_fd(ssl, new_sock);
            if (!ret)
            {
                printf(PREFIX "SSL_set_fd failed\n");
                exit(1);
            }
            int err = SSL_accept(ssl);
            fprintf(stderr, PREFIX "SSL_accept return %d\n", err);
            CHK_SSL(err);
            printf(PREFIX "SSL connection established!\n");
            int ret = verify_user(ssl, sa_client, new_sock);
            if (ret == -1)
                printf(PREFIX "Login failed!\n");
        }
        // 从SSL链路接收数据及判断客户端是否断开连接
        for (i = 0; i < MAX_SESSIONS; i++)
        {
            if (session_table[i].socket_fd <= 0)
                continue;
            if (FD_ISSET(session_table[i].socket_fd, &readfds))
            {
                int client_sock = session_table[i].socket_fd;
                SSL* ssl = session_table[i].ssl_session;
                sendto_TUN(ssl, client_sock, tunfd);
            }
        }
        ...
        // 从tun0接收数据到SSL链路
        if (FD_ISSET(tunfd, &readfds))
        {
            sendto_SSL(tunfd);
        }
    }
    ...
    return 0;
}

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

运行结果:
Linux C/C++实现SSL的应用层VPN (MiniVPN),C/C++,linux,c语言,c++,SSL,VPN

Linux C/C++实现SSL的应用层VPN (MiniVPN),C/C++,linux,c语言,c++,SSL,VPN

Linux添加虚拟网卡(tunctl添加虚拟网卡TUN):
Linux C/C++实现SSL的应用层VPN (MiniVPN),C/C++,linux,c语言,c++,SSL,VPN可以使用命令"route -n"来查看路由表:
Linux C/C++实现SSL的应用层VPN (MiniVPN),C/C++,linux,c语言,c++,SSL,VPN完成代码后,需要进行调试和测试,以确保VPN和SSL的正常工作,实现SSL的应用层VPN是一项复杂的任务,需要深入了解网络协议和安全原理。

总结

在VPN的实现过程中,SSL协议常常被用于对数据进行加密,从而确保数据的传输安全。因此,SSL VPN是使用SSL协议来实现的安全通信通道,提供更高级别的安全性。此外,VPN还可以隐藏用户的真实IP地址,提供匿名性和绕过地理限制。

Welcome to follow WeChat official account【程序猿编码文章来源地址https://www.toymoban.com/news/detail-721724.html

到了这里,关于Linux C/C++实现SSL的应用层VPN (MiniVPN)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】应用层协议:HTTP和HTTPS

    每个人都可以很喜欢每个人,但喜欢治不了病,喜欢买不了东西,喜欢不能当饭吃,喜欢很廉价… 1.1 URL的组成 1. 在之前的文章中我们实现了一个网络版本的计算器,在那个计算器中揉合了协议定制以及序列化反序列化的内容,我们当时也自己定制了一套协议标准,比如请求

    2024年02月10日
    浏览(46)
  • 【Linux】【驱动】应用层和驱动层传输数据

    Linux一切皆文件! 文件对应的操作有打开,关闭,读写设备节点对应的操作有打开,关闭,读写 当我们在应用层 read 设备节点的时候,就会触发我们驱动里面read 这个函数 当我们在应用层 write 设备节点的时候,就会触发我们驱动里面 write 这个函数 如下两个代码实现了数据的

    2024年02月12日
    浏览(39)
  • Linux 内核线程启动以及内核调用应用层程序

    #include linux/kthread.h //内核线程头文件   static task_struct *test_task; test_task = kthread_run(thread_function, NULL, \\\"test_thread_name\\\"); if(IS_ERR(test_task)) {         pr_err(\\\"test_thread_name create failn\\\"); } static int thread_function(void *arg) {     char *envp[3];     char *argv[3];     int ret= 0;     argv[0] = \\\"/bin/sh\\\";  

    2024年02月12日
    浏览(53)
  • Linux在应用层上使用I2C

    通常情况下i2c读写一般是在kernel中使用,但是在应用层上一样可以使用。在应用上可以通过读写/dev/i2c-x这个节点从而控制i2c接口进行读写数据。 通常一个SOC有多个I2C控制器,假设有这个SOC有3个控制器,我们会在/dev目录下看到i2c-0、i2c-1、i2c-2,计数从0开始。 1.首先使用的时

    2024年02月02日
    浏览(46)
  • 【Linux网络】网络应用层的 http 和 https协议

    在之前学习序列化和反序列化的时候,认识到主机之间传输结构数据的时候,最好是通过某种约定将结构数据序列化成一串字符串,接收方再通过反序列化将字符串转换成结构数据。以上说的这种约定,其实可以看成是用户层通信的一种协议,是由程序猿自己定的。   实际

    2024年02月02日
    浏览(60)
  • 【Linux】应用层协议序列化和反序列化

    欢迎来到Cefler的博客😁 🕌博客主页:折纸花满衣 🏠个人专栏:题目解析 🌎推荐文章:C++【智能指针】 前言 在正式代码开始前,会有一些前提知识引入 在网络应用层中,序列化(Serialization)和反序列化(Deserialization)是将数据转换为可在网络上传输的格式,并从网络接

    2024年04月23日
    浏览(38)
  • [Linux] 初识应用层协议: 序列化与反序列化、编码与解码、jsoncpp简单使用...

    有关Linux网络, 之前的文章已经简单演示介绍了 UDP 、 TCP 套接字编程 相关文章: [Linux] 网络编程 - 初见UDP套接字编程: 网络编程部分相关概念、TCP、UDP协议基本特点、网络字节序、socket接口使用、简单的UDP网络及聊天室实现… [Linux] 网络编程 - 初见TCP套接字编程: 实现简单的单

    2024年02月15日
    浏览(61)
  • zynq 使用AXI_dma 传输==pl到ps,linux驱动开发,应用层处理DMA数据

    在使用zynq输出处理时,会使用到pl和ps的数据传输,可供使用的方案有多种,由于我们的数据量较大打算,因此使用用以下两种方案处理: 1.使用pl直接写ddr3, 2.使用dma, 本次详细介绍使用axi_dma如何将pl的数据在linux应用层接收数据并处理,以及遇到的问题 fpga工程,我们使用

    2024年02月03日
    浏览(55)
  • 韦东山Linux驱动入门实验班(2)hello驱动---驱动层与应用层通讯,以及自动产生设备节点

    (1)学习韦东山老师的Linux,因为他讲的很精简,以至于很多人听不懂。接下来我讲介绍韦东山老师的驱动实验班的第二个Hello程序。 (2)注意,请先学习完视频再来看这个教程!本文仅供入门学习!如需深入,请搜索其他博客! (3)因为上一个教程已经讲的很详细了,所

    2024年02月05日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包