You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

147 lines
8.4 KiB

/* Обычный TLS 1.3 и HTTP-запрос проходят через REALITY fallback на локальный HTTPS. */
#define OPENSSL_API_COMPAT 0x10100000L
#include "stcp_server.h"
#include "utun_instance.h"
#include "../lib/debug_config.h"
#include "../lib/mem.h"
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <openssl/err.h>
#include <string.h>
#include <time.h>
#define CHECK(x) do { if (!(x)) { DEBUG_ERROR(DEBUG_CATEGORY_REALITY, "FAIL line=%d: %s", __LINE__, #x); return 1; } } while (0)
struct https_peer {
struct UASYNC *ua;
SSL *ssl;
void *socket_id;
socket_t sock;
uint8_t ready, done, failed;
uint8_t response[256]; size_t response_len;
};
struct https_server { struct UASYNC *ua; SSL_CTX *ctx; socket_t sock; struct https_peer peer; };
static const char response[] = "HTTP/1.1 200 OK\r\nContent-Length: 5\r\nConnection: close\r\n\r\nhello";
static void https_progress(socket_t sock, void *arg) {
struct https_peer *p = arg;
int rc;
if (!p->ready) {
rc = SSL_accept(p->ssl);
if (rc == 1) p->ready = 1;
else {
int error = SSL_get_error(p->ssl, rc);
if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) {
uasync_set_socket_write(p->ua, p->socket_id, error == SSL_ERROR_WANT_WRITE);
return;
}
DEBUG_ERROR(DEBUG_CATEGORY_REALITY, "HTTPS handshake failed: ssl=%d", error);
p->failed = 1;
return;
}
}
if (!p->done) {
uint8_t request[512];
rc = SSL_read(p->ssl, request, sizeof(request));
if (rc > 0) {
if (rc < 4 || memcmp(request, "GET ", 4)) { DEBUG_ERROR(DEBUG_CATEGORY_REALITY, "invalid HTTP request"); p->failed = 1; return; }
rc = SSL_write(p->ssl, response, sizeof(response) - 1);
if (rc != sizeof(response) - 1) { DEBUG_ERROR(DEBUG_CATEGORY_REALITY, "HTTPS response write failed"); p->failed = 1; return; }
p->done = 1;
uasync_set_socket_write(p->ua, p->socket_id, 0);
DEBUG_INFO(DEBUG_CATEGORY_REALITY, "local HTTPS received HTTP request through relay");
} else {
int error = SSL_get_error(p->ssl, rc);
if (error != SSL_ERROR_WANT_READ && error != SSL_ERROR_WANT_WRITE) {
DEBUG_ERROR(DEBUG_CATEGORY_REALITY, "HTTPS read failed: ssl=%d openssl=%lu", error, ERR_get_error());
p->failed = 1;
}
uasync_set_socket_write(p->ua, p->socket_id, error == SSL_ERROR_WANT_WRITE);
}
}
(void)sock;
}
static void https_accept(socket_t sock, void *arg) {
struct https_server *s = arg;
struct https_peer *p = &s->peer;
p->sock = accept(sock, NULL, NULL); p->ua = s->ua;
if (p->sock == SOCKET_INVALID) { p->failed = 1; return; }
socket_set_nonblocking(p->sock);
p->ssl = SSL_new(s->ctx);
if (!p->ssl || SSL_set_fd(p->ssl, p->sock) != 1) { DEBUG_ERROR(DEBUG_CATEGORY_REALITY, "HTTPS SSL setup failed"); p->failed = 1; return; }
p->socket_id = uasync_add_socket_t(s->ua, p->sock, https_progress, https_progress, NULL, "test_https", p);
if (!p->socket_id) { DEBUG_ERROR(DEBUG_CATEGORY_REALITY, "HTTPS socket registration failed"); p->failed = 1; }
}
static void unexpected_stcp(struct stcp_conn *c, void *arg) {
(void)c; (void)arg;
DEBUG_ERROR(DEBUG_CATEGORY_REALITY, "ordinary HTTPS client entered STCP");
}
static int client_step(SSL *client, int rc) {
if (rc > 0) return rc;
int error = SSL_get_error(client, rc);
return error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE ? 0 : -1;
}
int main(void) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO);
size_t allocated = u_get_allocated_count();
struct UASYNC *ua = uasync_create(); CHECK(ua);
struct UTUN_INSTANCE inst = {0}; inst.ua = ua;
struct SC_MYKEYS keys; CHECK(sc_generate_keypair(&keys) == SC_OK);
EVP_PKEY_CTX *key_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, NULL); EVP_PKEY *key = NULL;
CHECK(key_ctx && EVP_PKEY_keygen_init(key_ctx) == 1 && EVP_PKEY_keygen(key_ctx, &key) == 1);
X509 *cert = X509_new(); CHECK(cert);
CHECK(X509_set_version(cert, 2) && ASN1_INTEGER_set(X509_get_serialNumber(cert), 1));
CHECK(X509_gmtime_adj(X509_getm_notBefore(cert), 0) && X509_gmtime_adj(X509_getm_notAfter(cert), 3600));
X509_NAME *name = X509_get_subject_name(cert);
CHECK(X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (const unsigned char *)"localhost", -1, -1, 0));
CHECK(X509_set_issuer_name(cert, name) && X509_set_pubkey(cert, key) && X509_sign(cert, key, NULL) > 0);
struct https_server server = {0}; server.ua = ua; server.peer.sock = SOCKET_INVALID;
server.ctx = SSL_CTX_new(TLS_server_method()); SSL_CTX *client_ctx = SSL_CTX_new(TLS_client_method());
CHECK(server.ctx && client_ctx && SSL_CTX_use_certificate(server.ctx, cert) && SSL_CTX_use_PrivateKey(server.ctx, key));
CHECK(SSL_CTX_set_min_proto_version(server.ctx, TLS1_3_VERSION) && SSL_CTX_set_min_proto_version(client_ctx, TLS1_3_VERSION));
CHECK(SSL_CTX_set1_groups_list(client_ctx, "X25519") && SSL_CTX_set_ciphersuites(client_ctx, "TLS_AES_128_GCM_SHA256"));
SSL_CTX_set_num_tickets(server.ctx, 0); SSL_CTX_set_verify(client_ctx, SSL_VERIFY_NONE, NULL);
server.sock = socket(AF_INET, SOCK_STREAM, 0); CHECK(server.sock != SOCKET_INVALID);
struct sockaddr_in address = {0}; address.sin_family = AF_INET; address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
CHECK(!bind(server.sock, (struct sockaddr *)&address, sizeof(address)) && !listen(server.sock, 1));
socklen_t size = sizeof(address); CHECK(!getsockname(server.sock, (struct sockaddr *)&address, &size));
socket_set_nonblocking(server.sock);
CHECK(uasync_add_socket_t(ua, server.sock, https_accept, NULL, NULL, "test_https_listener", &server));
struct reality_config cfg; reality_config_set_defaults(&cfg);
cfg.enabled = 1; cfg.short_id_count = 1;
uint8_t pub[32]; CHECK(!reality_generate_keypair(cfg.private_key, pub));
snprintf(cfg.dest, sizeof(cfg.dest), "127.0.0.1:%u", ntohs(address.sin_port));
uint16_t port = 34000 + (uint16_t)(time(NULL) % 1000);
struct stcp_server *reality = stcp_server_create(ua, port, &keys, NULL, &inst, unexpected_stcp, NULL, NULL, NULL, AF_INET);
CHECK(reality); stcp_server_set_reality(reality, &cfg);
socket_t sock = socket(AF_INET, SOCK_STREAM, 0); CHECK(sock != SOCKET_INVALID);
address.sin_port = htons(port); CHECK(!connect(sock, (struct sockaddr *)&address, sizeof(address)));
socket_set_nonblocking(sock);
SSL *client = SSL_new(client_ctx); CHECK(client && SSL_set_fd(client, sock));
CHECK(SSL_set_tlsext_host_name(client, "localhost"));
int ready = 0;
for (unsigned i = 0; !ready && !server.peer.failed && i < 1000; i++) {
ready = client_step(client, SSL_connect(client)); CHECK(ready >= 0); uasync_poll(ua, 1);
}
CHECK(ready == 1 && SSL_version(client) == TLS1_3_VERSION);
const char request[] = "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n";
CHECK(SSL_write(client, request, sizeof(request) - 1) == sizeof(request) - 1);
uint8_t data[256]; size_t received = 0;
for (unsigned i = 0; received < sizeof(response) - 1 && !server.peer.failed && i < 1000; i++) {
int n = client_step(client, SSL_read(client, data + received, sizeof(data) - received));
CHECK(n >= 0); received += n; uasync_poll(ua, 1);
}
DEBUG_INFO(DEBUG_CATEGORY_REALITY, "HTTPS result: ready=%u done=%u failed=%u received=%zu", server.peer.ready, server.peer.done, server.peer.failed, received);
CHECK(!server.peer.failed && received == sizeof(response) - 1 && !memcmp(data, response, received));
CHECK(inst.reality_owner.relay_count == 1);
SSL_free(client); socket_close_wrapper(sock);
stcp_server_destroy(reality); reality_owner_cleanup(&inst.reality_owner);
if (server.peer.sock != SOCKET_INVALID) {
uasync_remove_socket_t(ua, server.peer.sock); SSL_free(server.peer.ssl); socket_close_wrapper(server.peer.sock);
}
uasync_remove_socket_t(ua, server.sock); socket_close_wrapper(server.sock);
SSL_CTX_free(client_ctx); SSL_CTX_free(server.ctx); X509_free(cert); EVP_PKEY_free(key); EVP_PKEY_CTX_free(key_ctx);
uasync_drain_immediate(ua); uasync_destroy(ua, 1); CHECK(u_get_allocated_count() == allocated);
DEBUG_INFO(DEBUG_CATEGORY_REALITY, "real TLS 1.3 + HTTP over fallback passed without leaked resources");
return 0;
}