aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/openvpn/dco.h14
-rw-r--r--src/openvpn/dco_freebsd.c81
-rw-r--r--src/openvpn/dco_linux.c7
-rw-r--r--src/openvpn/dco_win.c7
-rw-r--r--src/openvpn/multi.c30
-rw-r--r--src/openvpn/openvpn.h2
-rw-r--r--src/openvpn/ovpn_dco_freebsd.h1
7 files changed, 129 insertions, 13 deletions
diff --git a/src/openvpn/dco.h b/src/openvpn/dco.h
index e051db0..941060e 100644
--- a/src/openvpn/dco.h
+++ b/src/openvpn/dco.h
@@ -226,6 +226,14 @@ void dco_install_iroute(struct multi_context *m, struct multi_instance *mi,
void dco_delete_iroutes(struct multi_context *m, struct multi_instance *mi);
/**
+ * Update traffic statistics for all peers
+ *
+ * @param dco DCO device context
+ * @param m the server context
+ **/
+int dco_get_peer_stats(dco_context_t *dco, struct multi_context *m);
+
+/**
* Retrieve the list of ciphers supported by the current platform
*
* @return list of colon-separated ciphers
@@ -345,6 +353,12 @@ dco_delete_iroutes(struct multi_context *m, struct multi_instance *mi)
{
}
+static inline int
+dco_get_peer_stats(dco_context_t *dco, struct multi_context *m)
+{
+ return 0;
+}
+
static inline const char *
dco_get_supported_ciphers()
{
diff --git a/src/openvpn/dco_freebsd.c b/src/openvpn/dco_freebsd.c
index a52ac8c..694ec53 100644
--- a/src/openvpn/dco_freebsd.c
+++ b/src/openvpn/dco_freebsd.c
@@ -37,6 +37,7 @@
#include "dco.h"
#include "tun.h"
#include "crypto.h"
+#include "multi.h"
#include "ssl_common.h"
static nvlist_t *
@@ -641,6 +642,86 @@ dco_event_set(dco_context_t *dco, struct event_set *es, void *arg)
nvlist_destroy(nvl);
}
+static void
+dco_update_peer_stat(struct multi_context *m, uint32_t peerid, const nvlist_t *nvl)
+{
+ struct hash_element *he;
+ struct hash_iterator hi;
+
+ hash_iterator_init(m->hash, &hi);
+
+ while ((he = hash_iterator_next(&hi)))
+ {
+ struct multi_instance *mi = (struct multi_instance *) he->value;
+
+ if (mi->context.c2.tls_multi->peer_id != peerid)
+ {
+ continue;
+ }
+
+ mi->context.c2.dco_read_bytes = nvlist_get_number(nvl, "in");
+ mi->context.c2.dco_write_bytes = nvlist_get_number(nvl, "out");
+
+ return;
+ }
+
+ msg(M_INFO, "Peer %d returned by kernel, but not found locally", peerid);
+}
+
+int
+dco_get_peer_stats(dco_context_t *dco, struct multi_context *m)
+{
+
+ struct ifdrv drv;
+ uint8_t buf[4096];
+ nvlist_t *nvl;
+ const nvlist_t *const *nvpeers;
+ size_t npeers;
+ int ret;
+
+ if (!dco || !dco->open)
+ {
+ return 0;
+ }
+
+ CLEAR(drv);
+ snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
+ drv.ifd_cmd = OVPN_GET_PEER_STATS;
+ drv.ifd_len = sizeof(buf);
+ drv.ifd_data = buf;
+
+ ret = ioctl(dco->fd, SIOCGDRVSPEC, &drv);
+ if (ret)
+ {
+ msg(M_WARN | M_ERRNO, "Failed to get peer stats");
+ return -EINVAL;
+ }
+
+ nvl = nvlist_unpack(buf, drv.ifd_len, 0);
+ if (!nvl)
+ {
+ msg(M_WARN, "Failed to unpack nvlist");
+ return -EINVAL;
+ }
+
+ if (!nvlist_exists_nvlist_array(nvl, "peers"))
+ {
+ /* no peers */
+ return 0;
+ }
+
+ nvpeers = nvlist_get_nvlist_array(nvl, "peers", &npeers);
+ for (size_t i = 0; i < npeers; i++)
+ {
+ const nvlist_t *peer = nvpeers[i];
+ uint32_t peerid = nvlist_get_number(peer, "peerid");
+
+ dco_update_peer_stat(m, peerid, nvlist_get_nvlist(peer, "bytes"));
+ }
+
+ return 0;
+}
+
const char *
dco_get_supported_ciphers()
{
diff --git a/src/openvpn/dco_linux.c b/src/openvpn/dco_linux.c
index 1093582..0306cec 100644
--- a/src/openvpn/dco_linux.c
+++ b/src/openvpn/dco_linux.c
@@ -911,6 +911,13 @@ nla_put_failure:
return ret;
}
+int
+dco_get_peer_stats(dco_context_t *dco, struct multi_context *m)
+{
+ /* Not implemented. */
+ return 0;
+}
+
bool
dco_available(int msglevel)
{
diff --git a/src/openvpn/dco_win.c b/src/openvpn/dco_win.c
index 48a1755..68ec931 100644
--- a/src/openvpn/dco_win.c
+++ b/src/openvpn/dco_win.c
@@ -399,6 +399,13 @@ dco_do_write(dco_context_t *dco, int peer_id, struct buffer *buf)
return 0;
}
+int
+dco_get_peer_stats(dco_context_t *dco, struct multi_context *m)
+{
+ /* Not implemented. */
+ return 0;
+}
+
void
dco_event_set(dco_context_t *dco, struct event_set *es, void *arg)
{
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 0a23c2b..38da87b 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -538,29 +538,31 @@ multi_del_iroutes(struct multi_context *m,
}
static void
-setenv_stats(struct context *c)
+setenv_stats(struct multi_context *m, struct context *c)
{
- setenv_counter(c->c2.es, "bytes_received", c->c2.link_read_bytes);
- setenv_counter(c->c2.es, "bytes_sent", c->c2.link_write_bytes);
+ dco_get_peer_stats(&m->top.c1.tuntap->dco, m);
+
+ setenv_counter(c->c2.es, "bytes_received", c->c2.link_read_bytes + c->c2.dco_read_bytes);
+ setenv_counter(c->c2.es, "bytes_sent", c->c2.link_write_bytes + c->c2.dco_write_bytes);
}
static void
-multi_client_disconnect_setenv(struct multi_instance *mi)
+multi_client_disconnect_setenv(struct multi_context *m, struct multi_instance *mi)
{
/* setenv client real IP address */
setenv_trusted(mi->context.c2.es, get_link_socket_info(&mi->context));
/* setenv stats */
- setenv_stats(&mi->context);
+ setenv_stats(m, &mi->context);
/* setenv connection duration */
setenv_long_long(mi->context.c2.es, "time_duration", now - mi->created);
}
static void
-multi_client_disconnect_script(struct multi_instance *mi)
+multi_client_disconnect_script(struct multi_context *m, struct multi_instance *mi)
{
- multi_client_disconnect_setenv(mi);
+ multi_client_disconnect_setenv(m, mi);
if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT))
{
@@ -667,7 +669,7 @@ multi_close_instance(struct multi_context *m,
if (mi->context.c2.tls_multi->multi_state >= CAS_CONNECT_DONE)
{
- multi_client_disconnect_script(mi);
+ multi_client_disconnect_script(m, mi);
}
close_context(&mi->context, SIGTERM, CC_GC_FREE);
@@ -837,6 +839,8 @@ multi_print_status(struct multi_context *m, struct status_output *so, const int
status_reset(so);
+ dco_get_peer_stats(&m->top.c1.tuntap->dco, m);
+
if (version == 1)
{
/*
@@ -856,8 +860,8 @@ multi_print_status(struct multi_context *m, struct status_output *so, const int
status_printf(so, "%s,%s," counter_format "," counter_format ",%s",
tls_common_name(mi->context.c2.tls_multi, false),
mroute_addr_print(&mi->real, &gc),
- mi->context.c2.link_read_bytes,
- mi->context.c2.link_write_bytes,
+ mi->context.c2.link_read_bytes + mi->context.c2.dco_read_bytes,
+ mi->context.c2.link_write_bytes + mi->context.c2.dco_write_bytes,
time_string(mi->created, 0, false, &gc));
}
gc_free(&gc);
@@ -932,8 +936,8 @@ multi_print_status(struct multi_context *m, struct status_output *so, const int
sep, mroute_addr_print(&mi->real, &gc),
sep, print_in_addr_t(mi->reporting_addr, IA_EMPTY_IF_UNDEF, &gc),
sep, print_in6_addr(mi->reporting_addr_ipv6, IA_EMPTY_IF_UNDEF, &gc),
- sep, mi->context.c2.link_read_bytes,
- sep, mi->context.c2.link_write_bytes,
+ sep, mi->context.c2.link_read_bytes + mi->context.c2.dco_read_bytes,
+ sep, mi->context.c2.link_write_bytes + mi->context.c2.dco_write_bytes,
sep, time_string(mi->created, 0, false, &gc),
sep, (unsigned int)mi->created,
sep, tls_username(mi->context.c2.tls_multi, false),
@@ -2752,7 +2756,7 @@ multi_connection_established(struct multi_context *m, struct multi_instance *mi)
* did not fail */
if (mi->context.c2.tls_multi->multi_state == CAS_PENDING_DEFERRED_PARTIAL)
{
- multi_client_disconnect_script(mi);
+ multi_client_disconnect_script(m, mi);
}
mi->context.c2.tls_multi->multi_state = CAS_FAILED;
diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h
index c543cbf..5981e4d 100644
--- a/src/openvpn/openvpn.h
+++ b/src/openvpn/openvpn.h
@@ -267,8 +267,10 @@ struct context_2
counter_type tun_read_bytes;
counter_type tun_write_bytes;
counter_type link_read_bytes;
+ counter_type dco_read_bytes;
counter_type link_read_bytes_auth;
counter_type link_write_bytes;
+ counter_type dco_write_bytes;
#ifdef PACKET_TRUNCATION_CHECK
counter_type n_trunc_tun_read;
counter_type n_trunc_tun_write;
diff --git a/src/openvpn/ovpn_dco_freebsd.h b/src/openvpn/ovpn_dco_freebsd.h
index cf92d59..cc90111 100644
--- a/src/openvpn/ovpn_dco_freebsd.h
+++ b/src/openvpn/ovpn_dco_freebsd.h
@@ -61,5 +61,6 @@ enum ovpn_key_cipher {
#define OVPN_POLL_PKT _IO('D', 10)
#define OVPN_GET_PKT _IO('D', 11)
#define OVPN_SET_IFMODE _IO('D', 12)
+#define OVPN_GET_PEER_STATS _IO('D', 13)
#endif /* ifndef _NET_IF_OVPN_H_ */