#include "connection.h"
#include <arpa/inet.h>
+#include <assert.h>
#include <errno.h>
+#include <limits.h>
+#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
+#include <stdint.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <unistd.h>
+#if GNUTLS_VERSION_NUMBER <= 0x020b00
/* Necessary for GnuTLS when used with threads. */
#include <gcrypt.h>
GCRY_THREAD_OPTION_PTHREAD_IMPL;
+#endif
/* Size of ringbuffer. */
#define RINGBUFFER_SIZE 10
-/* Bit size of Diffie-Hellman key exchange parameters. */
-#define DH_SIZE 1024
-
/* For gnutls_*() functions. */
#define GNUTLS_ERROR_EXIT(error, message) \
/* Server should shut down. Set by SIGINT handler. */
-static volatile int done = 0;
+static volatile int done; /* = 0 */
/* Number of threads. */
static size_t thread_count;
static void parse_arguments(int argc, char **argv);
static void print_usage(const char *argv);
-static char *slurp_file(const char *path);
+static char *slurp_text_file(const char *path);
static void initialize_gnutls(void);
static void deinitialize_gnutls(void);
}
#ifdef USE_IPV4_ONLY
- server_socket = socket(PF_INET, SOCK_STREAM, 0);
+ server_socket = socket(AF_INET, SOCK_STREAM, 0);
#else
- server_socket = socket(PF_INET6, SOCK_STREAM, 0);
+ server_socket = socket(AF_INET6, SOCK_STREAM, 0);
#endif
if (server_socket < 0) {
perror("socket()");
}
/* Fast rebinding for debug mode, could cause invalid packets. */
- if (global_log_level >= LOG_DEBUG_LEVEL) {
+ if (global_log_level >= LOG_DEBUG1_LEVEL) {
int socket_option = 1;
setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR,
&socket_option, sizeof(socket_option));
return EXIT_FAILURE;
}
- if (global_log_level >= LOG_DEBUG_LEVEL) {
+ if (global_log_level >= LOG_DEBUG1_LEVEL) {
printf("tlsproxy %s\n", VERSION);
printf("Listening for connections on port %d.\n", port);
+ printf("Priority string: %s.\n", PROXY_TLS_PRIORITIES);
if (global_proxy_host != NULL && global_proxy_port != NULL) {
printf("Using proxy: %s:%s.\n", global_proxy_host,
free(global_proxy_host);
free(global_proxy_port);
+ free(global_http_digest_authorization);
return EXIT_FAILURE;
}
/* Default values. */
thread_count = 10;
#ifdef DEBUG
- global_log_level = LOG_DEBUG_LEVEL;
+ global_log_level = LOG_DEBUG2_LEVEL;
#else
global_log_level = LOG_WARNING_LEVEL;
#endif
while ((option = getopt(argc, argv, "a:d:p:t:uh?")) != -1) {
switch (option) {
case 'a': {
- http_digest_authorization = slurp_file(optarg);
- if (http_digest_authorization == NULL) {
+ global_http_digest_authorization = slurp_text_file(optarg);
+ if (global_http_digest_authorization == NULL) {
fprintf(stderr, "failed to open authorization file '%s': ",
optarg);
perror("");
exit(EXIT_FAILURE);
- } else if (strlen(http_digest_authorization) == 0) {
+ } else if (strlen(global_http_digest_authorization) == 0) {
fprintf(stderr, "empty authorization file '%s'\n",
optarg);
exit(EXIT_FAILURE);
}
/* Just in case the file has a trailing newline. */
- strtok(http_digest_authorization, "\r\n");
+ strtok(global_http_digest_authorization, "\r\n");
break;
}
memcpy(global_proxy_host, optarg, (size_t)(position - optarg));
global_proxy_host[position - optarg] = '\0';
- global_proxy_port = malloc(strlen(position + 1) + 1);
+ global_proxy_host = strdup(position + 1);
if (global_proxy_port == NULL) {
- perror("malloc()");
+ perror("strdup()");
exit(EXIT_FAILURE);
}
- strcpy(global_proxy_port, position + 1);
break;
}
argv);
fprintf(stderr, "\n");
fprintf(stderr, "-a digest authentication file [default: none]\n");
- fprintf(stderr, "-d debug level: 0=errors only, 2=debug [default: 1]\n");
+ fprintf(stderr, "-d debug level: 0=errors only, 2=debug, 3=more debug [default: 1]\n");
fprintf(stderr, "-p proxy hostname and port\n");
fprintf(stderr, "-t number of threads [default: 10]\n");
fprintf(stderr, "-u passthrough connection if no certificate is stored \
fprintf(stderr, " WARNING: might be a security problem!\n");
}
+#if 0
+static void log_function_gnutls(int level, const char *string) {
+ (void)level;
+ fprintf(stderr, " => %s", string);
+}
+#endif
+
static void initialize_gnutls(void) {
int result;
+ char *dh_parameters;
+ gnutls_datum_t dh_parameters_datum;
+
+/* Recent versions of GnuTLS automatically initialize the cryptography layer
+ * in gnutls_global_init(), including a thread-safe setup. */
+#if GNUTLS_VERSION_NUMBER <= 0x020b00
gcry_error_t error;
/* Thread safe setup. Must be called before gnutls_global_init(). */
gcry_strerror(error));
exit(EXIT_FAILURE);
}
+#endif
+
+ if (gnutls_check_version(GNUTLS_VERSION) == NULL) {
+ fprintf(stderr, "gnutls_check_version(): version mismatch, "
+ "expected at least '" GNUTLS_VERSION "'\n");
+ exit(EXIT_FAILURE);
+ }
/* Initialize GnuTLS. */
result = gnutls_global_init();
GNUTLS_ERROR_EXIT(result, "gnutls_global_init()");
+#if 0
+ gnutls_global_set_log_level(10);
+ gnutls_global_set_log_function(log_function_gnutls);
+#endif
+
/* Setup GnuTLS cipher suites. */
- result = gnutls_priority_init(&global_tls_priority_cache, "NORMAL", NULL);
+ result = gnutls_priority_init(&global_tls_priority_cache,
+ PROXY_TLS_PRIORITIES, NULL);
GNUTLS_ERROR_EXIT(result, "gnutls_priority_init()");
- /* Generate Diffie-Hellman parameters. */
+ /* Read Diffie-Hellman parameters. */
+ dh_parameters = slurp_text_file(PROXY_DH_PATH);
+ if (dh_parameters == NULL) {
+ fprintf(stderr, PROXY_DH_PATH " missing, "
+ "use `tlsproxy-setup` to create it\n");
+ exit(EXIT_FAILURE);
+ }
+ dh_parameters_datum.data = (unsigned char *)dh_parameters;
+ assert(strlen(dh_parameters) <= UINT_MAX);
+ dh_parameters_datum.size = (unsigned int)(strlen(dh_parameters));
+
result = gnutls_dh_params_init(&global_tls_dh_params);
GNUTLS_ERROR_EXIT(result, "gnutls_dh_params_init()");
- result = gnutls_dh_params_generate2(global_tls_dh_params, DH_SIZE);
- GNUTLS_ERROR_EXIT(result, "gnutls_dh_params_generate2()");
+ result = gnutls_dh_params_import_pkcs3(global_tls_dh_params,
+ &dh_parameters_datum,
+ GNUTLS_X509_FMT_PEM);
+ GNUTLS_ERROR_EXIT(result, "gnutls_dh_params_import_pkcs3()");
+
+ free(dh_parameters);
}
static void deinitialize_gnutls(void) {
gnutls_dh_params_deinit(global_tls_dh_params);
return NULL;
}
-static char *slurp_file(const char *path) {
+static char *slurp_text_file(const char *path) {
struct stat stat;
size_t size_read;
char *content = NULL;