Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TLS 模式下,对被检测程序的性能影响。 #463

Closed
yifannir opened this issue Jan 23, 2024 · 9 comments
Closed

TLS 模式下,对被检测程序的性能影响。 #463

yifannir opened this issue Jan 23, 2024 · 9 comments
Assignees
Labels
help wanted Extra attention is needed improve question Further information is requested

Comments

@yifannir
Copy link

机器开一个Nginx服务,然后使用wget https下载文件,开启ecapture与关闭ecapture有接近20%的性能下降,只测试ssl write函数的话更有接近5倍的性能下降,分析主要耗时是在内核态与用户态的切换上,这个如何解决?

@cfc4n
Copy link
Member

cfc4n commented Jan 23, 2024

有性能报告吗?

@cfc4n cfc4n added the question Further information is requested label Jan 23, 2024
@yifannir
Copy link
Author

yifannir commented Jan 23, 2024

公司内网数据发不出来,这个在第一个wget下很好复现,我可以口述一下,使用nginx在本机启动,然后本地使用 wget https://xxxx 下载一个大文件,观察ecapture关闭前后的两次下载带宽就可以发现明显影响。如果是第二种的话,同样针对刚才的Nginx服务,使用

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define SERVER "127.0.0.1"
#define PORT 443
#define REQUEST "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"
#define TEST_CNT 10000000

char g_requests[TEST_CNT][strlen(REQUEST) + 1];
int create_socket(const char *host, int port) {
    int sockfd;
    struct sockaddr_in dest_addr;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(port);
    dest_addr.sin_addr.s_addr = inet_addr(host);

    memset(&(dest_addr.sin_zero), '\0', 8);

    if (connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr)) == -1) {
        perror("connect");
        exit(EXIT_FAILURE);
    }

    return sockfd;
}

void init_request() {
    int i;
    for (i = 0; i < TEST_CNT; i++) {
        memcpy(g_requests[i], REQUEST, strlen(REQUEST));
    }

}

int main() {
    SSL_CTX *ctx;
    SSL *ssl;
    int server;
    char reply[4096];

    SSL_library_init();
    SSL_load_error_strings();
    OpenSSL_add_all_algorithms();

    ctx = SSL_CTX_new(TLS_client_method());
    if (ctx == NULL) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    server = create_socket(SERVER, PORT);
    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, server);
    SSL_connect(ssl);

    init_request();
    int request_len = strlen(REQUEST);

    // Perform SSL_write performance test
    int i;
    for (i = 0; i < TEST_CNT; i++) {
        char *request = g_requests[i];
        int bytes_written = SSL_write(ssl, request, request_len);  // Perform SSL_write
        if (bytes_written <= 0) {
            fprintf(stderr, "SSL_write failed\n");
            ERR_print_errors_fp(stderr);
            break;
        }
    }

    SSL_read(ssl, reply, sizeof(reply));  // Read server response

    SSL_free(ssl);
    close(server);
    SSL_CTX_free(ctx);
    return 0;
}

去运行,性能差异大概是 开启前 6s左右跑完,开启后,30s跑完,

@cfc4n
Copy link
Member

cfc4n commented Jan 23, 2024

启用eCapture   的命令是什么?

另外,你可以试试 keylog模式,只HOOK了一个函数,性能开销比较小,之后你用wireshark来读取。

./ecapture tls -m keylog -keylogfile=openssl_keylog.log

@yifannir
Copy link
Author

避免刷屏影响,使用的就是这个输出文件模式。这个您可以测试一下,应该不难复现。

@cfc4n
Copy link
Member

cfc4n commented Jan 23, 2024

你的服务器系统版本是哪个? openssl的类库版本呢?

@yifannir
Copy link
Author

Ubuntu2204,libssl.so.6

@cfc4n cfc4n self-assigned this Jan 24, 2024
@cfc4n
Copy link
Member

cfc4n commented Jan 27, 2024

确实存在这个性能问题,我近期尝试优化一下。
image

@cfc4n cfc4n added help wanted Extra attention is needed improve labels Jan 27, 2024
cfc4n added a commit that referenced this issue Jan 27, 2024
* When calling `SSL_connect` in the OpenSSL library in a client role or `SSL_accept` in a server role, the execution flow ultimately enters the `state_machine` function in `ssl/statem/statem.c` for TLS handshake.
* Therefore, the optional scope is functions within this `state_machine` function that start with an uppercase `SSL`.
* When using OpenSSL synchronously, a successful TLS handshake returns 1, i.e., `ret = 1`. Thus, after this variable is assigned, the called functions can obtain the desired memory data.
* Under this premise, the only function within the `state_machine` function that meets the requirements is `SSL_get_wbio`.
* Adding an alternate HOOK function, `SSL_in_before`, to the scope.

Signed-off-by: CFC4N <cfc4n.cs@gmail.com>
@cfc4n
Copy link
Member

cfc4n commented Jan 27, 2024

优化结果来了,10000000次的数据发送,耗时从30降低到7.1,比不启用eCapture多了1.5S,目前先做到这样,可以试试PR #471

cfc4n added a commit that referenced this issue Jan 28, 2024
* When calling `SSL_connect` in the OpenSSL library in a client role or `SSL_accept` in a server role, the execution flow ultimately enters the `state_machine` function in `ssl/statem/statem.c` for TLS handshake.
* Therefore, the optional scope is functions within this `state_machine` function that start with an uppercase `SSL`.
* When using OpenSSL synchronously, a successful TLS handshake returns 1, i.e., `ret = 1`. Thus, after this variable is assigned, the called functions can obtain the desired memory data.
* Under this premise, the only function within the `state_machine` function that meets the requirements is `SSL_get_wbio`.
* Adding an alternate HOOK function, `SSL_in_before`, to the scope.

Signed-off-by: CFC4N <cfc4n.cs@gmail.com>
cfc4n added a commit that referenced this issue Jan 28, 2024
* When calling `SSL_connect` in the OpenSSL library in a client role or `SSL_accept` in a server role, the execution flow ultimately enters the `state_machine` function in `ssl/statem/statem.c` for TLS handshake.
* Therefore, the optional scope is functions within this `state_machine` function that start with an uppercase `SSL`.
* When using OpenSSL synchronously, a successful TLS handshake returns 1, i.e., `ret = 1`. Thus, after this variable is assigned, the called functions can obtain the desired memory data.
* Under this premise, the only function within the `state_machine` function that meets the requirements is `SSL_get_wbio`.
* Adding an alternate HOOK function, `SSL_in_before`, to the scope.

Signed-off-by: CFC4N <cfc4n.cs@gmail.com>
@cfc4n
Copy link
Member

cfc4n commented Jan 31, 2024

ping?

@cfc4n cfc4n closed this as completed Feb 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed improve question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants