feat: Initial code
This commit is contained in:
197
src/proxy.c
Normal file
197
src/proxy.c
Normal file
@@ -0,0 +1,197 @@
|
||||
#include "proxy.h"
|
||||
#include "doh.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include <netdb.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define MAX_REQUEST_SIZE 8192
|
||||
#define MAX_URL_LENGTH 2048
|
||||
#define THREAD_POOL_SIZE 20
|
||||
|
||||
typedef struct {
|
||||
int client_sock;
|
||||
} thread_arg_t;
|
||||
|
||||
// Extract hostname from HTTP request
|
||||
char* extract_host(const char* request) {
|
||||
static char host[MAX_URL_LENGTH];
|
||||
const char* host_header = strstr(request, "Host: ");
|
||||
|
||||
if (host_header) {
|
||||
host_header += 6; // Skip "Host: "
|
||||
int i = 0;
|
||||
while (host_header[i] && host_header[i] != '\r' && host_header[i] != '\n' && i < MAX_URL_LENGTH - 1) {
|
||||
host[i] = host_header[i];
|
||||
i++;
|
||||
}
|
||||
host[i] = '\0';
|
||||
return host;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Handle client connection in a separate thread
|
||||
void* handle_client(void* arg) {
|
||||
thread_arg_t* thread_arg = (thread_arg_t*)arg;
|
||||
int client_sock = thread_arg->client_sock;
|
||||
free(thread_arg);
|
||||
|
||||
char request[MAX_REQUEST_SIZE];
|
||||
char buffer[MAX_REQUEST_SIZE];
|
||||
ssize_t bytes_received = recv(client_sock, request, sizeof(request) - 1, 0);
|
||||
|
||||
if (bytes_received <= 0) {
|
||||
close(client_sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
request[bytes_received] = '\0';
|
||||
|
||||
// Extract host from request
|
||||
char* host = extract_host(request);
|
||||
if (!host) {
|
||||
printf("Failed to extract host from request\n");
|
||||
close(client_sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("Proxying request to: %s\n", host);
|
||||
|
||||
// Resolve hostname using DoH
|
||||
char ip_addr[INET6_ADDRSTRLEN];
|
||||
if (resolve_doh(host, ip_addr, sizeof(ip_addr)) != 0) {
|
||||
printf("Failed to resolve hostname using DoH: %s\n", host);
|
||||
close(client_sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("Resolved %s to %s\n", host, ip_addr);
|
||||
|
||||
// Connect to the target server
|
||||
struct sockaddr_in server_addr;
|
||||
int server_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (server_sock < 0) {
|
||||
perror("Cannot create socket to server");
|
||||
close(client_sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&server_addr, 0, sizeof(server_addr));
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_addr.s_addr = inet_addr(ip_addr);
|
||||
server_addr.sin_port = htons(80); // Default to HTTP port
|
||||
|
||||
if (connect(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
|
||||
perror("Cannot connect to server");
|
||||
close(server_sock);
|
||||
close(client_sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Forward the request to the server
|
||||
if (send(server_sock, request, bytes_received, 0) < 0) {
|
||||
perror("Failed to send request to server");
|
||||
close(server_sock);
|
||||
close(client_sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Receive response from server and forward to client
|
||||
while ((bytes_received = recv(server_sock, buffer, sizeof(buffer), 0)) > 0) {
|
||||
if (send(client_sock, buffer, bytes_received, 0) < 0) {
|
||||
perror("Failed to send response to client");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close(server_sock);
|
||||
close(client_sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int start_proxy_server(int port) {
|
||||
int server_sock, client_sock;
|
||||
struct sockaddr_in server_addr, client_addr;
|
||||
socklen_t client_len = sizeof(client_addr);
|
||||
|
||||
// Create socket
|
||||
server_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (server_sock < 0) {
|
||||
perror("Cannot create socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Allow reuse of address
|
||||
int opt = 1;
|
||||
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
|
||||
perror("setsockopt failed");
|
||||
close(server_sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Initialize server address
|
||||
memset(&server_addr, 0, sizeof(server_addr));
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
server_addr.sin_port = htons(port);
|
||||
|
||||
// Bind socket
|
||||
if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
|
||||
perror("Bind failed");
|
||||
close(server_sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Listen for connections
|
||||
if (listen(server_sock, 10) < 0) {
|
||||
perror("Listen failed");
|
||||
close(server_sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Proxy server listening on port %d\n", port);
|
||||
|
||||
// Accept and handle client connections
|
||||
while (1) {
|
||||
client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &client_len);
|
||||
if (client_sock < 0) {
|
||||
perror("Accept failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("New connection from %s:%d\n",
|
||||
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
|
||||
|
||||
// Create thread argument
|
||||
thread_arg_t* thread_arg = malloc(sizeof(thread_arg_t));
|
||||
if (!thread_arg) {
|
||||
perror("Failed to allocate memory for thread argument");
|
||||
close(client_sock);
|
||||
continue;
|
||||
}
|
||||
thread_arg->client_sock = client_sock;
|
||||
|
||||
// Create thread to handle client
|
||||
pthread_t thread_id;
|
||||
if (pthread_create(&thread_id, NULL, handle_client, thread_arg) != 0) {
|
||||
perror("Failed to create thread");
|
||||
free(thread_arg);
|
||||
close(client_sock);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Detach thread to allow it to clean up automatically
|
||||
pthread_detach(thread_id);
|
||||
}
|
||||
|
||||
close(server_sock);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user