feat: Get started on DANE

This commit is contained in:
2025-04-23 17:59:43 +10:00
parent 92f4f19d32
commit ad60c9f2b4
10 changed files with 1400 additions and 5 deletions

View File

@@ -1,5 +1,6 @@
#include "proxy.h"
#include "doh.h"
#include "dane.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -11,6 +12,10 @@
#include <netdb.h>
#include <ctype.h>
#include <signal.h>
#include <errno.h>
#include <sys/stat.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define MAX_REQUEST_SIZE 8192
#define MAX_URL_LENGTH 2048
@@ -91,8 +96,186 @@ int extract_port(const char* request) {
return default_port;
}
// Handle HTTPS CONNECT tunneling
void handle_https_tunnel(int client_sock, int server_sock) {
// Initialize SSL context for intercepting HTTPS
ssl_context_t* init_ssl_context(const char* cert_path, const char* key_path) {
ssl_context_t* ssl_ctx = malloc(sizeof(ssl_context_t));
if (!ssl_ctx) {
fprintf(stderr, "Failed to allocate memory for SSL context\n");
return NULL;
}
// Initialize SSL context
ssl_ctx->ctx = SSL_CTX_new(TLS_server_method());
if (!ssl_ctx->ctx) {
fprintf(stderr, "Failed to create SSL context\n");
free(ssl_ctx);
return NULL;
}
// Configure SSL context
SSL_CTX_set_options(ssl_ctx->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION);
// Load certificate and private key
if (SSL_CTX_use_certificate_file(ssl_ctx->ctx, cert_path, SSL_FILETYPE_PEM) <= 0) {
fprintf(stderr, "Failed to load certificate: %s\n", cert_path);
SSL_CTX_free(ssl_ctx->ctx);
free(ssl_ctx);
return NULL;
}
if (SSL_CTX_use_PrivateKey_file(ssl_ctx->ctx, key_path, SSL_FILETYPE_PEM) <= 0) {
fprintf(stderr, "Failed to load private key: %s\n", key_path);
SSL_CTX_free(ssl_ctx->ctx);
free(ssl_ctx);
return NULL;
}
// Verify private key
if (!SSL_CTX_check_private_key(ssl_ctx->ctx)) {
fprintf(stderr, "Private key does not match the certificate\n");
SSL_CTX_free(ssl_ctx->ctx);
free(ssl_ctx);
return NULL;
}
return ssl_ctx;
}
// Handle HTTPS CONNECT tunneling with DANE verification
void handle_https_tunnel(int client_sock, int server_sock, const char* hostname, const char* ip_addr) {
// Unused parameter
(void)ip_addr;
// Check if we have DANE records for this domain
int has_dane = is_dane_available(hostname);
if (has_dane) {
printf("DANE records found for %s, will verify certificate\n", hostname);
char cert_path[256];
char key_path[256];
snprintf(cert_path, sizeof(cert_path), "certs/%s.crt", hostname);
snprintf(key_path, sizeof(key_path), "certs/%s.key", hostname);
// Generate a trusted certificate for this domain
if (!generate_trusted_cert(hostname, cert_path, key_path)) {
fprintf(stderr, "Failed to generate trusted certificate for %s\n", hostname);
// Fall back to regular tunneling
handle_regular_https_tunnel(client_sock, server_sock);
return;
}
// Initialize SSL context with our certificate
ssl_context_t* client_ctx = init_ssl_context(cert_path, key_path);
if (!client_ctx) {
fprintf(stderr, "Failed to initialize SSL context\n");
handle_regular_https_tunnel(client_sock, server_sock);
return;
}
// Connect to the server with SSL to verify DANE
SSL_CTX* server_ctx = SSL_CTX_new(TLS_client_method());
if (!server_ctx) {
fprintf(stderr, "Failed to create server SSL context\n");
SSL_CTX_free(client_ctx->ctx);
free(client_ctx);
handle_regular_https_tunnel(client_sock, server_sock);
return;
}
SSL* server_ssl = SSL_new(server_ctx);
SSL_set_fd(server_ssl, server_sock);
// Set SNI hostname
SSL_set_tlsext_host_name(server_ssl, hostname);
// Connect to the server with SSL
if (SSL_connect(server_ssl) <= 0) {
fprintf(stderr, "SSL connection to server failed\n");
SSL_free(server_ssl);
SSL_CTX_free(server_ctx);
SSL_CTX_free(client_ctx->ctx);
free(client_ctx);
handle_regular_https_tunnel(client_sock, server_sock);
return;
}
// Get the server's certificate
X509* server_cert = SSL_get_peer_certificate(server_ssl);
if (!server_cert) {
fprintf(stderr, "Failed to get server certificate\n");
SSL_free(server_ssl);
SSL_CTX_free(server_ctx);
SSL_CTX_free(client_ctx->ctx);
free(client_ctx);
handle_regular_https_tunnel(client_sock, server_sock);
return;
}
// Verify the certificate against DANE
int dane_verified = verify_cert_against_dane(hostname, server_cert);
if (dane_verified <= 0) {
fprintf(stderr, "DANE verification failed for %s\n", hostname);
X509_free(server_cert);
SSL_free(server_ssl);
SSL_CTX_free(server_ctx);
SSL_CTX_free(client_ctx->ctx);
free(client_ctx);
handle_regular_https_tunnel(client_sock, server_sock);
return;
}
printf("DANE verification successful for %s\n", hostname);
// Send 200 Connection Established to the client
const char* success_response = "HTTP/1.1 200 Connection Established\r\n\r\n";
if (send(client_sock, success_response, strlen(success_response), 0) < 0) {
perror("Failed to send connection established response");
X509_free(server_cert);
SSL_free(server_ssl);
SSL_CTX_free(server_ctx);
SSL_CTX_free(client_ctx->ctx);
free(client_ctx);
return;
}
// Initialize SSL connection with the client
client_ctx->ssl = SSL_new(client_ctx->ctx);
SSL_set_fd(client_ctx->ssl, client_sock);
if (SSL_accept(client_ctx->ssl) <= 0) {
fprintf(stderr, "SSL accept failed\n");
SSL_free(client_ctx->ssl);
X509_free(server_cert);
SSL_free(server_ssl);
SSL_CTX_free(server_ctx);
SSL_CTX_free(client_ctx->ctx);
free(client_ctx);
return;
}
printf("SSL connection established with client for %s\n", hostname);
// Now we have SSL connections to both client and server
// We can forward data between them
ssl_tunnel_data(client_ctx->ssl, server_ssl);
// Clean up
SSL_free(client_ctx->ssl);
X509_free(server_cert);
SSL_free(server_ssl);
SSL_CTX_free(server_ctx);
SSL_CTX_free(client_ctx->ctx);
free(client_ctx);
} else {
// No DANE records, use regular tunneling
handle_regular_https_tunnel(client_sock, server_sock);
}
}
// Regular HTTPS tunneling without interception
void handle_regular_https_tunnel(int client_sock, int server_sock) {
fd_set read_fds;
char buffer[MAX_REQUEST_SIZE];
int max_fd = (client_sock > server_sock) ? client_sock : server_sock;
@@ -129,6 +312,62 @@ void handle_https_tunnel(int client_sock, int server_sock) {
}
}
// Forward data between SSL connections
void ssl_tunnel_data(SSL* client_ssl, SSL* server_ssl) {
fd_set read_fds;
char buffer[MAX_REQUEST_SIZE];
int client_fd = SSL_get_fd(client_ssl);
int server_fd = SSL_get_fd(server_ssl);
int max_fd = (client_fd > server_fd) ? client_fd : server_fd;
while (1) {
FD_ZERO(&read_fds);
FD_SET(client_fd, &read_fds);
FD_SET(server_fd, &read_fds);
if (select(max_fd + 1, &read_fds, NULL, NULL, NULL) < 0) {
perror("Select failed");
break;
}
if (FD_ISSET(client_fd, &read_fds)) {
int bytes_received = SSL_read(client_ssl, buffer, sizeof(buffer));
if (bytes_received <= 0) {
int err = SSL_get_error(client_ssl, bytes_received);
if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
break;
}
} else {
int bytes_sent = SSL_write(server_ssl, buffer, bytes_received);
if (bytes_sent <= 0) {
int err = SSL_get_error(server_ssl, bytes_sent);
if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
break;
}
}
}
}
if (FD_ISSET(server_fd, &read_fds)) {
int bytes_received = SSL_read(server_ssl, buffer, sizeof(buffer));
if (bytes_received <= 0) {
int err = SSL_get_error(server_ssl, bytes_received);
if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
break;
}
} else {
int bytes_sent = SSL_write(client_ssl, buffer, bytes_received);
if (bytes_sent <= 0) {
int err = SSL_get_error(client_ssl, bytes_sent);
if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
break;
}
}
}
}
}
}
// Modify HTTP request for direct server communication
char* rewrite_http_request(const char* original_request, size_t* new_length) {
// Find the first line ending
@@ -261,8 +500,8 @@ void* handle_client(void* arg) {
}
if (is_connect) {
// HTTPS: Handle CONNECT tunnel
handle_https_tunnel(client_sock, server_sock);
// HTTPS: Handle CONNECT tunnel with DANE support
handle_https_tunnel(client_sock, server_sock, host, ip_addr);
} else {
// HTTP: Rewrite the request and forward it
printf("HTTP request received, rewriting for server...\n");
@@ -341,6 +580,12 @@ int start_proxy_server(int port) {
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
// Initialize proxy components
if (proxy_init() != 0) {
fprintf(stderr, "Failed to initialize proxy server\n");
return 1;
}
// Create socket
server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock < 0) {
@@ -419,10 +664,27 @@ int start_proxy_server(int port) {
return 0;
}
// Initialize the proxy server
int proxy_init() {
// Initialize DANE support
if (!dane_init()) {
fprintf(stderr, "Failed to initialize DANE support\n");
return 1;
}
return 0;
}
// Clean up proxy resources
void proxy_cleanup() {
dane_cleanup();
}
// Signal handler for graceful termination
void handle_signal(int sig) {
if (sig == SIGINT) {
printf("\nShutting down proxy server...\n");
proxy_cleanup();
exit(0);
}
}