mirror of
https://github.com/EndPositive/slipstream.git
synced 2025-10-08 12:25:04 +00:00
cli
This commit is contained in:
parent
163a02dbd4
commit
cb4a29a239
12 changed files with 518 additions and 218 deletions
|
|
@ -1,69 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "slipstream.h"
|
||||
|
||||
static void usage(char const * sample_name)
|
||||
{
|
||||
fprintf(stderr, "Usage:\n");
|
||||
fprintf(stderr, " %s client listen_port slipstream_server_name slipstream_server_port domain_name\n", sample_name);
|
||||
fprintf(stderr, " %s server listen_port cert key target_server_name target_server_port domain_name\n", sample_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int get_port(char const* sample_name, char const* port_arg)
|
||||
{
|
||||
int server_port = atoi(port_arg);
|
||||
if (server_port <= 0) {
|
||||
fprintf(stderr, "Invalid port: %s\n", port_arg);
|
||||
usage(sample_name);
|
||||
}
|
||||
|
||||
return server_port;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int exit_code = 0;
|
||||
#ifdef _WINDOWS
|
||||
WSADATA wsaData = { 0 };
|
||||
(void)WSA_START(MAKEWORD(2, 2), &wsaData);
|
||||
#endif
|
||||
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
setbuf(stderr, NULL);
|
||||
if (argc < 2) {
|
||||
usage(argv[0]);
|
||||
}
|
||||
else if (strcmp(argv[1], "client") == 0) {
|
||||
if (argc != 7) {
|
||||
usage(argv[0]);
|
||||
}
|
||||
else {
|
||||
int local_port = atoi(argv[2]);
|
||||
char const* resolver_addresses_filename = argv[3];
|
||||
const char* domain_name = argv[4];
|
||||
const char* cc_algo_id = argv[5];
|
||||
bool gso = strcmp(argv[6], "true") == 0;
|
||||
exit_code = picoquic_slipstream_client(local_port, resolver_addresses_filename, domain_name, cc_algo_id, gso);
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[1], "server") == 0) {
|
||||
if (argc != 8) {
|
||||
usage(argv[0]);
|
||||
}
|
||||
else {
|
||||
int server_port = get_port(argv[0], argv[2]);
|
||||
int remote_port = get_port(argv[0], argv[6]);
|
||||
const char* domain_name = argv[7];
|
||||
exit_code = picoquic_slipstream_server(server_port, argv[3], argv[4], argv[5], remote_port, domain_name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
exit(exit_code);
|
||||
}
|
||||
|
|
@ -21,11 +21,11 @@
|
|||
#include "picoquic_config.h"
|
||||
#include "slipstream.h"
|
||||
#include "slipstream_inline_dots.h"
|
||||
#include "slipstream_resolver_addresses.h"
|
||||
#include "slipstream_utils.h"
|
||||
#include "SPCDNS/src/dns.h"
|
||||
#include "SPCDNS/src/mappings.h"
|
||||
|
||||
|
||||
typedef struct st_slipstream_client_stream_ctx_t {
|
||||
struct st_slipstream_client_stream_ctx_t* next_stream;
|
||||
struct st_slipstream_client_stream_ctx_t* previous_stream;
|
||||
|
|
@ -683,7 +683,7 @@ static int slipstream_connect(struct sockaddr_storage* server_address,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int picoquic_slipstream_client(int listen_port, char const* resolver_addresses_filename, const char* domain_name, const char* cc_algo_id, bool gso) {
|
||||
int picoquic_slipstream_client(int listen_port, struct st_address_t* server_addresses, size_t server_address_count, const char* domain_name, const char* cc_algo_id, bool gso) {
|
||||
/* Start: start the QUIC process */
|
||||
int ret = 0;
|
||||
uint64_t current_time = 0;
|
||||
|
|
@ -691,9 +691,9 @@ int picoquic_slipstream_client(int listen_port, char const* resolver_addresses_f
|
|||
client_domain_name = strdup(domain_name);
|
||||
client_domain_name_len = strlen(domain_name);
|
||||
|
||||
// int mtu = 1200;
|
||||
// int mtu = 129;
|
||||
int mtu = 145;
|
||||
double mtu_d = 240 - (double) client_domain_name_len;
|
||||
mtu_d = mtu_d / 1.6;
|
||||
int mtu = (int) mtu_d;
|
||||
|
||||
/* Create config */
|
||||
picoquic_quic_config_t config;
|
||||
|
|
@ -736,12 +736,9 @@ int picoquic_slipstream_client(int listen_port, char const* resolver_addresses_f
|
|||
// picoquic_set_log_level(quic, 1);
|
||||
// TODO: idle timeout?
|
||||
|
||||
/* Read the server address list from the file */
|
||||
client_ctx.server_addresses = read_resolver_addresses(resolver_addresses_filename, &client_ctx.server_address_count);
|
||||
if (!client_ctx.server_addresses) {
|
||||
printf("Failed to read IP addresses\n");
|
||||
return 1;
|
||||
}
|
||||
/* Parse the server addresses directly */
|
||||
client_ctx.server_addresses = server_addresses;
|
||||
client_ctx.server_address_count = server_address_count;
|
||||
|
||||
picoquic_cnx_t* cnx = NULL;
|
||||
ret = slipstream_connect(&client_ctx.server_addresses[0].server_address, quic, &cnx, &client_ctx);
|
||||
|
|
|
|||
179
src/slipstream_client_cli.c
Normal file
179
src/slipstream_client_cli.c
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <argp.h>
|
||||
#include <picosocks.h>
|
||||
#include "slipstream.h"
|
||||
|
||||
const char* argp_program_version = "slipstream-client 0.1";
|
||||
const char* argp_program_bug_address = "github.com/EndPositive/slipstream";
|
||||
|
||||
/* Program documentation */
|
||||
static char doc[] = "slipstream-client - A high-performance covert channel over DNS (client)\v";
|
||||
|
||||
/* A description of the arguments we accept. */
|
||||
static char args_doc[] = "";
|
||||
|
||||
/* Client mode options */
|
||||
static struct argp_option options[] = {
|
||||
{"tcp-listen-port", 'l', "PORT", 0, "Listen port (default: 5201)", 0},
|
||||
{"resolver", 'r', "RESOLVER", 0, "Slipstream server resolver address (e.g., 1.1.1.1 or 8.8.8.8:53). Can be specified multiple times. (Required)", 0},
|
||||
{"congestion-control", 'c', "ALGO", 0, "Congestion control algorithm (bbr, dcubic) (default: dcubic)", 0},
|
||||
{"gso", 'g', "BOOL", OPTION_ARG_OPTIONAL, "GSO enabled (true/false) (default: false). Use --gso or --gso=true to enable.", 0},
|
||||
{"domain", 'd', "DOMAIN", 0, "Domain name used for the covert channel (Required)", 0},
|
||||
{0} // End of options
|
||||
};
|
||||
|
||||
/* Used by main to communicate with parse options. */
|
||||
struct arguments {
|
||||
int listen_port;
|
||||
char* domain_name;
|
||||
struct st_address_t* resolver_addresses;
|
||||
size_t resolver_count;
|
||||
char* cc_algo_id;
|
||||
bool gso;
|
||||
};
|
||||
|
||||
/* Client mode parser */
|
||||
static error_t parse_opt(int key, char* arg, struct argp_state* state) {
|
||||
struct arguments* arguments = state->input;
|
||||
|
||||
switch (key) {
|
||||
case 'd':
|
||||
arguments->domain_name = arg;
|
||||
break;
|
||||
case 'l':
|
||||
arguments->listen_port = atoi(arg);
|
||||
if (arguments->listen_port <= 0 || arguments->listen_port > 65535) {
|
||||
argp_error(state, "Invalid TCP listen port number: %s", arg);
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
{
|
||||
// Allocate or reallocate the resolver addresses array
|
||||
struct st_address_t* new_resolvers = realloc(arguments->resolver_addresses,
|
||||
(arguments->resolver_count + 1) * sizeof(struct st_address_t));
|
||||
if (!new_resolvers) {
|
||||
argp_error(state, "Memory allocation failed for resolver address");
|
||||
return ARGP_ERR_UNKNOWN; // Signal error
|
||||
}
|
||||
arguments->resolver_addresses = new_resolvers;
|
||||
|
||||
char server_name[256]; // Increased size for FQDNs
|
||||
int server_port = 53; // Default DNS port
|
||||
|
||||
// Try parsing with port first, then without
|
||||
if (sscanf(arg, "%255[^:]:%d", server_name, &server_port) < 1) {
|
||||
// If sscanf fails, maybe it's just an IP/hostname without port?
|
||||
strncpy(server_name, arg, sizeof(server_name) -1);
|
||||
server_name[sizeof(server_name)-1] = '\0'; // Ensure null termination
|
||||
// Keep default port 53
|
||||
}
|
||||
|
||||
if (server_port <= 0 || server_port > 65535) {
|
||||
argp_error(state, "Invalid port number in resolver address: %s", arg);
|
||||
}
|
||||
|
||||
int is_name = 0; // We don't use this flag downstream currently
|
||||
if (picoquic_get_server_address(server_name, server_port, &arguments->resolver_addresses[arguments->resolver_count].server_address, &is_name) != 0) {
|
||||
argp_error(state, "Cannot resolve resolver address '%s' port %d", server_name, server_port);
|
||||
}
|
||||
|
||||
arguments->resolver_count++;
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
// Consider adding validation for supported algorithms here
|
||||
arguments->cc_algo_id = arg;
|
||||
break;
|
||||
case 'g':
|
||||
// Handle optional argument for --gso
|
||||
if (arg == NULL || strcmp(arg, "true") == 0) {
|
||||
arguments->gso = true;
|
||||
} else if (strcmp(arg, "false") == 0) {
|
||||
arguments->gso = false;
|
||||
} else {
|
||||
argp_error(state, "Invalid boolean value for --gso: '%s'. Use 'true' or 'false'.", arg);
|
||||
}
|
||||
break;
|
||||
case ARGP_KEY_ARG:
|
||||
// No positional arguments expected
|
||||
argp_usage(state);
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Define the argp structure for client
|
||||
static struct argp argp = {options, parse_opt, args_doc, doc, 0, 0, 0};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int exit_code = 0;
|
||||
struct arguments arguments;
|
||||
|
||||
#ifdef _WINDOWS
|
||||
WSADATA wsaData = { 0 };
|
||||
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
if (iResult != 0) {
|
||||
fprintf(stderr, "WSAStartup failed: %d\n", iResult);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Default values */
|
||||
memset(&arguments, 0, sizeof(arguments));
|
||||
arguments.listen_port = 5201; // Default TCP listen port
|
||||
arguments.cc_algo_id = "dcubic"; // Default CC algo
|
||||
arguments.gso = false; // Default GSO state
|
||||
arguments.resolver_addresses = NULL;
|
||||
arguments.resolver_count = 0;
|
||||
|
||||
// Ensure output buffers are flushed immediately (useful for debugging/logging)
|
||||
setbuf(stdout, NULL);
|
||||
setbuf(stderr, NULL);
|
||||
|
||||
// Parse command line arguments
|
||||
error_t parse_err = argp_parse(&argp, argc, argv, 0, NULL, &arguments);
|
||||
if (parse_err) {
|
||||
// argp should have printed an error message already
|
||||
exit(1); // Exit if parsing failed
|
||||
}
|
||||
|
||||
/* Check mandatory client arguments */
|
||||
bool client_args_ok = true;
|
||||
if (arguments.domain_name == NULL) {
|
||||
fprintf(stderr, "Client error: Missing required --domain option\n");
|
||||
client_args_ok = false;
|
||||
}
|
||||
if (arguments.resolver_count == 0) {
|
||||
fprintf(stderr, "Client error: Missing required --resolver option (at least one required)\n");
|
||||
client_args_ok = false;
|
||||
}
|
||||
|
||||
if (!client_args_ok) {
|
||||
// Show specific client help message
|
||||
argp_help(&argp, stderr, ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR, "slipstream-client");
|
||||
// argp_help with ARGP_HELP_EXIT_ERR will exit, no need for exit(1) here
|
||||
}
|
||||
|
||||
exit_code = picoquic_slipstream_client(
|
||||
arguments.listen_port,
|
||||
arguments.resolver_addresses,
|
||||
arguments.resolver_count,
|
||||
arguments.domain_name,
|
||||
arguments.cc_algo_id,
|
||||
arguments.gso
|
||||
);
|
||||
|
||||
// Free allocated memory for resolver addresses
|
||||
free(arguments.resolver_addresses);
|
||||
|
||||
#ifdef _WINDOWS
|
||||
WSACleanup();
|
||||
#endif
|
||||
|
||||
exit(exit_code);
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
#include "slipstream_resolver_addresses.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <picosocks.h>
|
||||
|
||||
#define MAX_IP_LENGTH 20
|
||||
#define INITIAL_CAPACITY 10
|
||||
#define MAX_LINE_LENGTH 50
|
||||
#define DEFAULT_PORT 53
|
||||
|
||||
struct st_address_t* read_resolver_addresses(const char *resolver_addresses_filename, size_t *count) {
|
||||
*count = 0;
|
||||
|
||||
FILE *fp = fopen(resolver_addresses_filename, "r");
|
||||
if (!fp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int capacity = INITIAL_CAPACITY;
|
||||
struct st_address_t* server_address = calloc(capacity, sizeof(struct st_address_t));
|
||||
if (!server_address) {
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char line[MAX_LINE_LENGTH];
|
||||
int valid_addresses = 0;
|
||||
|
||||
while (fgets(line, MAX_LINE_LENGTH, fp)) {
|
||||
// Remove newline
|
||||
line[strcspn(line, "\n")] = '\0';
|
||||
|
||||
// Skip empty or whitespace-only lines
|
||||
if (strlen(line) == 0 || strspn(line, " \t") == strlen(line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Resize array if needed
|
||||
if (valid_addresses == capacity) {
|
||||
capacity *= 2;
|
||||
struct st_address_t* temp = realloc(server_address, capacity * sizeof(struct st_address_t));
|
||||
if (!temp) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
free(server_address);
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
server_address = temp;
|
||||
}
|
||||
|
||||
char server_name[MAX_IP_LENGTH];
|
||||
int server_port = DEFAULT_PORT;
|
||||
|
||||
// Parse line for IP and optional port
|
||||
if (sscanf(line, "%s %d", server_name, &server_port) < 1) {
|
||||
continue; // Invalid format
|
||||
}
|
||||
|
||||
printf("Adding %s:%d\n", server_name, server_port);
|
||||
|
||||
int is_name = 0;
|
||||
if (picoquic_get_server_address(server_name, server_port, &server_address[valid_addresses].server_address, &is_name) != 0) {
|
||||
fprintf(stderr, "Cannot get the IP address for <%s> port <%d>\n", server_name, server_port);
|
||||
continue; // Skip invalid addresses instead of failing
|
||||
}
|
||||
valid_addresses++;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
*count = valid_addresses;
|
||||
|
||||
// Trim excess memory if needed
|
||||
if (valid_addresses < capacity) {
|
||||
struct st_address_t* temp = realloc(server_address, valid_addresses * sizeof(struct st_address_t));
|
||||
if (temp) {
|
||||
server_address = temp;
|
||||
}
|
||||
}
|
||||
|
||||
return server_address;
|
||||
}
|
||||
|
|
@ -640,15 +640,14 @@ void server_sighandler(int signum) {
|
|||
}
|
||||
|
||||
int picoquic_slipstream_server(int server_port, const char* server_cert, const char* server_key,
|
||||
char const* upstream_name, int upstream_port, const char* domain_name) {
|
||||
struct sockaddr_storage* target_address, const char* domain_name) {
|
||||
/* Start: start the QUIC process with cert and key files */
|
||||
int ret = 0;
|
||||
uint64_t current_time = 0;
|
||||
slipstream_server_ctx_t default_context = {0};
|
||||
DBG_PRINTF("Starting Picoquic Sample server on port %d", server_port);
|
||||
|
||||
int is_name = 0;
|
||||
picoquic_get_server_address(upstream_name, upstream_port, &default_context.upstream_addr, &is_name);
|
||||
// Store the target address directly - no need to resolve it here anymore
|
||||
memcpy(&default_context.upstream_addr, target_address, sizeof(struct sockaddr_storage));
|
||||
|
||||
server_domain_name = strdup(domain_name);
|
||||
server_domain_name_len = strlen(domain_name);
|
||||
|
|
@ -731,3 +730,4 @@ int picoquic_slipstream_server(int server_port, const char* server_cert, const c
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
154
src/slipstream_server_cli.c
Normal file
154
src/slipstream_server_cli.c
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <argp.h>
|
||||
#include <picosocks.h>
|
||||
#include "slipstream.h"
|
||||
|
||||
const char* argp_program_version = "slipstream-server 0.1";
|
||||
const char* argp_program_bug_address = "github.com/EndPositive/slipstream";
|
||||
|
||||
/* Program documentation */
|
||||
static char doc[] = "slipstream-server - A high-performance covert channel over DNS (server)\v";
|
||||
|
||||
/* A description of the arguments we accept. */
|
||||
static char args_doc[] = "";
|
||||
|
||||
/* Server mode options */
|
||||
static struct argp_option options[] = {
|
||||
{"dns-listen-port", 'l', "PORT", 0, "DNS listen port (default: 53)", 0},
|
||||
{"target-address", 'a', "ADDRESS", 0, "Target server address (default: 127.0.0.1:5201)", 0},
|
||||
{"cert", 'c', "CERT", 0, "Certificate file path (default: certs/cert.pem)", 0},
|
||||
{"key", 'k', "KEY", 0, "Private key file path (default: certs/key.pem)", 0},
|
||||
{"domain", 'd', "DOMAIN", 0, "Domain name this server is authoritative for (Required)", 0},
|
||||
{0} // End of options
|
||||
};
|
||||
|
||||
/* Used by main to communicate with parse options. */
|
||||
struct arguments {
|
||||
int listen_port;
|
||||
char* domain_name;
|
||||
char* cert_file;
|
||||
char* key_file;
|
||||
struct sockaddr_storage target_address;
|
||||
};
|
||||
|
||||
/* Server mode parser */
|
||||
static error_t parse_opt(int key, char* arg, struct argp_state* state) {
|
||||
struct arguments* arguments = state->input;
|
||||
|
||||
switch (key) {
|
||||
case 'd':
|
||||
arguments->domain_name = arg;
|
||||
break;
|
||||
case 'l':
|
||||
arguments->listen_port = atoi(arg);
|
||||
if (arguments->listen_port <= 0 || arguments->listen_port > 65535) {
|
||||
argp_error(state, "Invalid DNS listen port number: %s", arg);
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
arguments->cert_file = arg;
|
||||
break;
|
||||
case 'k':
|
||||
arguments->key_file = arg;
|
||||
break;
|
||||
case 'a':
|
||||
{
|
||||
char server_name[256]; // Increased size for FQDNs
|
||||
int server_port = 5201; // Default upstream port
|
||||
|
||||
// Try parsing with port first, then without
|
||||
if (sscanf(arg, "%255[^:]:%d", server_name, &server_port) < 1) {
|
||||
// If sscanf fails, maybe it's just an IP/hostname without port?
|
||||
strncpy(server_name, arg, sizeof(server_name) - 1);
|
||||
server_name[sizeof(server_name) - 1] = '\0'; // Ensure null termination
|
||||
// Keep default port 5201
|
||||
}
|
||||
|
||||
if (server_port <= 0 || server_port > 65535) {
|
||||
argp_error(state, "Invalid port number in target address: %s", arg);
|
||||
}
|
||||
|
||||
int is_name = 0;
|
||||
if (picoquic_get_server_address(server_name, server_port, &arguments->target_address, &is_name) != 0) {
|
||||
argp_error(state, "Cannot resolve target address '%s' port %d", server_name, server_port);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ARGP_KEY_ARG:
|
||||
// No positional arguments expected
|
||||
argp_usage(state);
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Define the argp structure for server
|
||||
static struct argp argp = {options, parse_opt, args_doc, doc, 0, 0, 0};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int exit_code = 0;
|
||||
struct arguments arguments;
|
||||
|
||||
#ifdef _WINDOWS
|
||||
WSADATA wsaData = { 0 };
|
||||
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
if (iResult != 0) {
|
||||
fprintf(stderr, "WSAStartup failed: %d\n", iResult);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Default values */
|
||||
memset(&arguments, 0, sizeof(arguments));
|
||||
arguments.listen_port = 53; // Default DNS listen port
|
||||
arguments.cert_file = "certs/cert.pem"; // Default cert path
|
||||
arguments.key_file = "certs/key.pem"; // Default key path
|
||||
|
||||
// Set default target address (127.0.0.1:5201)
|
||||
int is_name = 0;
|
||||
if (picoquic_get_server_address("127.0.0.1", 5201, &arguments.target_address, &is_name) != 0) {
|
||||
fprintf(stderr, "Failed to set default target address\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Ensure output buffers are flushed immediately
|
||||
setbuf(stdout, NULL);
|
||||
setbuf(stderr, NULL);
|
||||
|
||||
// Parse command line arguments
|
||||
error_t parse_err = argp_parse(&argp, argc, argv, 0, NULL, &arguments);
|
||||
if (parse_err) {
|
||||
// argp should have printed an error message already
|
||||
exit(1); // Exit if parsing failed
|
||||
}
|
||||
|
||||
/* Check mandatory server arguments */
|
||||
bool server_args_ok = true;
|
||||
if (arguments.domain_name == NULL) {
|
||||
fprintf(stderr, "Server error: Missing required --domain option\n");
|
||||
server_args_ok = false;
|
||||
}
|
||||
|
||||
if (!server_args_ok) {
|
||||
argp_help(&argp, stderr, ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR, "slipstream-server");
|
||||
}
|
||||
|
||||
exit_code = picoquic_slipstream_server(
|
||||
arguments.listen_port,
|
||||
arguments.cert_file,
|
||||
arguments.key_file,
|
||||
&arguments.target_address,
|
||||
arguments.domain_name
|
||||
);
|
||||
|
||||
#ifdef _WINDOWS
|
||||
WSACleanup();
|
||||
#endif
|
||||
|
||||
exit(exit_code);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue