Skip to content

Commit

Permalink
Added status-file and status-interval options
Browse files Browse the repository at this point in the history
  • Loading branch information
mobrembski authored and Michał Obrembski committed Jan 20, 2021
1 parent d24362a commit f871b45
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 8 deletions.
12 changes: 12 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ const struct vpn_config invalid_cfg = {
.user_agent = NULL,
.hostcheck = NULL,
.check_virtual_desktop = NULL,
.status_file = {'\0'},
.status_interval = 0
};

/*
Expand Down Expand Up @@ -449,6 +451,12 @@ int load_config(struct vpn_config *cfg, const char *filename)
} else if (strcmp(key, "check-virtual-desktop") == 0) {
free(cfg->check_virtual_desktop);
cfg->check_virtual_desktop = strdup(val);
} else if (strcmp(key, "status-file") == 0) {
strcpy(cfg->status_file, val);
} else if (strcmp(key, "status-interval") == 0) {
unsigned long status_interval = strtoul(val, NULL, 0);

cfg->status_interval = status_interval;
} else {
log_warn("Bad key in config file: \"%s\".\n", key);
goto err_free;
Expand Down Expand Up @@ -600,4 +608,8 @@ void merge_config(struct vpn_config *dst, struct vpn_config *src)
dst->hostcheck = src->hostcheck;
if (src->check_virtual_desktop != invalid_cfg.check_virtual_desktop)
dst->check_virtual_desktop = src->check_virtual_desktop;
if (src->status_file[0])
strcpy(dst->status_file, src->status_file);
if (src->status_interval != invalid_cfg.status_interval)
dst->status_interval = src->status_interval;
}
2 changes: 2 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ struct vpn_config {
char *pinentry;
char iface_name[FIELD_SIZE + 1];
char realm[FIELD_SIZE + 1];
char status_file[FIELD_SIZE + 1];
unsigned int status_interval;

int set_routes;
int set_dns;
Expand Down
78 changes: 71 additions & 7 deletions src/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ static struct in_addr ip_addr;
static struct in_addr ns1_addr;
static struct in_addr ns2_addr;
static char dns_suffix[MAX_DOMAIN_LENGTH];
static const char *status_file;

int get_sig_received(void)
{
Expand Down Expand Up @@ -594,7 +595,6 @@ static void *if_config(void *arg)
struct tunnel *tunnel = (struct tunnel *) arg;
int timeout = 60000000; // one minute

current_state = &tunnel->state;
log_debug("%s thread\n", __func__);

// Wait for the right moment to configure IP interface
Expand Down Expand Up @@ -625,28 +625,47 @@ static void *if_config(void *arg)
return NULL;
}

static void print_statistics(void)
static void save_stats(void)
{
FILE *fp;
const char *state_str;

if (current_state != NULL) {
switch (*current_state) {
case STATE_DOWN: {
log_info("State: disconnected\n");
state_str = "State: disconnected";
break;
}
case STATE_CONNECTING: {
log_info("State: connecting\n");
state_str = "State: connecting";
break;
}
case STATE_UP: {
log_info("State: connected\n");
state_str = "State: connected";
break;
}
case STATE_DISCONNECTING: {
log_info("State: disconnecting\n");
state_str = "State: disconnecting";
break;
}
}
}
if (status_file[0] != '\0') {
fp = fopen(status_file, "w");
if (fp != NULL) {
fprintf(fp, "State: %s\n", state_str);
fprintf(fp, "Received bytes: %lu\n", total_received_bytes);
fprintf(fp, "Transmitted bytes: %lu\n", total_transmitted_bytes);
fprintf(fp, "IP Address: %s\n", inet_ntoa(ip_addr));
fprintf(fp, "NSS1 Address: %s\n", inet_ntoa(ns1_addr));
fprintf(fp, "NSS2 Address: %s\n", inet_ntoa(ns2_addr));
fprintf(fp, "Domain: %s\n", dns_suffix);
fclose(fp);
} else {
log_error(" Cannot create status file!\n");
}
}
log_info("State: %s\n", state_str);
log_info("Received bytes: %lu\n", total_received_bytes);
log_info("Transmitted bytes: %lu\n", total_transmitted_bytes);
log_info("IP Address: %s\n", inet_ntoa(ip_addr));
Expand All @@ -655,10 +674,33 @@ static void print_statistics(void)
log_info("Domain: %s\n", dns_suffix);
}

/*
* Thread to print statistics
*/
static void *status_thread(void *arg)
{
struct tunnel *tunnel = (struct tunnel *) arg;

log_debug("%s thread\n", __func__);

// Wait for the right moment to configure IP interface
SEM_WAIT(&sem_if_config);
if (tunnel->config->status_file[0] != '\0') {
while (1) {
current_state = &tunnel->state;
save_stats();
log_debug("Sleeping statistics thread for %u seconds...",
tunnel->config->status_interval);
sleep(tunnel->config->status_interval);
}
}
return NULL;
}

static void sig_handler(int signo)
{
if (signo == SIGUSR1) {
print_statistics();
save_stats();
} else {
sig_received = signo;
if (signo == SIGINT || signo == SIGTERM)
Expand All @@ -677,6 +719,7 @@ int io_loop(struct tunnel *tunnel)
pthread_t ssl_read_thread;
pthread_t ssl_write_thread;
pthread_t if_config_thread;
pthread_t stats_thread;

SEM_INIT(&sem_pppd_ready, 0, 0);
SEM_INIT(&sem_if_config, 0, 0);
Expand All @@ -688,6 +731,7 @@ int io_loop(struct tunnel *tunnel)
init_ssl_locks();

init_hdlc();
status_file = tunnel->config->status_file;

/*
* I noticed that using TCP_NODELAY (i.e. disabling Nagle's algorithm)
Expand Down Expand Up @@ -759,6 +803,14 @@ int io_loop(struct tunnel *tunnel)
goto err_thread;
}

if (status_file[0] != '\0' && tunnel->config->status_interval != 0) {
ret = pthread_create(&stats_thread, NULL, status_thread, tunnel);
if (ret != 0) {
log_debug("Error creating status_thread: %s\n", strerror(ret));
goto err_thread;
}
}

#if !HAVE_MACH_MACH_H
// Restore the signal for the main thread
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
Expand All @@ -772,6 +824,11 @@ int io_loop(struct tunnel *tunnel)
ret = pthread_cancel(if_config_thread);
if (ret != 0)
log_debug("Error canceling if_config_thread: %s\n", strerror(ret));
if (status_file[0] != '\0') {
ret = pthread_cancel(stats_thread);
if (ret != 0)
log_debug("Error canceling stats_thread: %s\n", strerror(ret));
}

ret = pthread_cancel(ssl_write_thread);
if (ret != 0)
Expand All @@ -791,6 +848,13 @@ int io_loop(struct tunnel *tunnel)

log_info("Cleanup, joining threads...\n");
// failure to clean is a possible zombie thread, consider it fatal
if (status_file[0] != '\0' && tunnel->config->status_interval != 0) {
ret = pthread_join(stats_thread, NULL);
if (ret != 0) {
log_debug("Error joining stats_thread: %s\n", strerror(ret));
fatal = 1;
}
}
ret = pthread_join(if_config_thread, NULL);
if (ret != 0) {
log_debug("Error joining if_config_thread: %s\n", strerror(ret));
Expand Down
34 changes: 33 additions & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,11 @@ PPPD_USAGE \
" certificate will be matched against this value.\n" \
" <digest> is the X509 certificate's sha256 sum.\n" \
" This option can be used multiple times to trust\n" \
" several certificates.\n"
" several certificates.\n" \
" --status Create a status file with statistics.\n" \
" --status-interval Interval between updating status file. \n " \
" If status file is not set, then print it on log.\n" \
" Printing is disabled by default.\n"

#define help_options_part2 \
" --insecure-ssl Do not disable insecure SSL protocols/ciphers.\n" \
Expand Down Expand Up @@ -208,6 +212,8 @@ int main(int argc, char **argv)
.use_syslog = 0,
.half_internet_routes = 0,
.persistent = 0,
.status_file = {'\0'},
.status_interval = 0,
#if HAVE_RESOLVCONF
.use_resolvconf = USE_RESOLVCONF,
#endif
Expand Down Expand Up @@ -267,6 +273,8 @@ int main(int argc, char **argv)
{"cipher-list", required_argument, NULL, 0},
{"min-tls", required_argument, NULL, 0},
{"seclevel-1", no_argument, &cli_cfg.seclevel_1, 1},
{"status-file", required_argument, NULL, 0},
{"status-interval", required_argument, NULL, 0},
#if HAVE_USR_SBIN_PPPD
{"pppd-use-peerdns", required_argument, NULL, 0},
{"pppd-no-peerdns", no_argument, &cli_cfg.pppd_use_peerdns, 0},
Expand Down Expand Up @@ -304,6 +312,7 @@ int main(int argc, char **argv)
/* If this option set a flag, do nothing else now. */
if (long_options[option_index].flag != 0)
break;
log_debug("%s\n", long_options[option_index].name);
if (strcmp(long_options[option_index].name,
"version") == 0) {
printf(VERSION "\n");
Expand Down Expand Up @@ -498,6 +507,26 @@ int main(int argc, char **argv)
cli_cfg.set_dns = set_dns;
break;
}
if (strcmp(long_options[option_index].name,
"status-file") == 0) {
log_debug(" COpying %s\n", optarg);
strncpy(cli_cfg.status_file, optarg, FIELD_SIZE);
cli_cfg.status_file[FIELD_SIZE] = '\0';
log_debug(" COpying %s\n", cli_cfg.status_file);
break;
}
if (strcmp(long_options[option_index].name,
"status-interval") == 0) {
long status_interval = strtol(optarg, NULL, 0);

if (status_interval < 0 || status_interval > UINT_MAX) {
log_warn("Bad status_interval option: \"%s\"\n",
optarg);
break;
}
cli_cfg.status_interval = status_interval;
break;
}
goto user_error;
case 'h':
printf("%s%s%s%s%s%s%s", usage, summary,
Expand Down Expand Up @@ -617,6 +646,9 @@ int main(int argc, char **argv)
cfg.password = strdup("");
if (cfg.otp[0] != '\0')
log_debug("One-time password = \"%s\"\n", cfg.otp);
if (cfg.status_file[0] != '\0')
log_debug("Config status-file = \"%s\"\n", cfg.status_file);
log_debug("Config status-interval = \"%u\"\n", cfg.status_interval);

if (geteuid() != 0) {
log_error("This process was not spawned with root privileges, which are required.\n");
Expand Down

0 comments on commit f871b45

Please sign in to comment.