Commit 37316927 authored by Ralph Schmieder's avatar Ralph Schmieder Committed by David Woodhouse

Add --passtos option to copy TOS/TCLASS from VPN packets

This allows prioritised queuing of outbound packets. It is only of local
significance (and importance) as it will influence queueing on the CPE
which is typically the only place where this will be in effect. And the
most effective place as the CPE is usually the bottleneck where all
applications compete for limited upstream bandwidth.

SPs do set the DSCP to 0 anyway at the trust boundary (which is the next
hop from the CPE). Same goes for large corporations which also either
reset the DSCP or have it set according to their policy, not the user's.

It is implemented as an 'opt-in' using the --passtos command line switch
in accordance with the OpenVPN implementation
Signed-off-by: default avatarRalph Schmieder <ralph.schmieder@gmail.com>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 7d3b728e
......@@ -1020,6 +1020,38 @@ int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout)
struct pkt *send_pkt = this;
int ret;
/* If TOS optname is set, we want to copy the TOS/TCLASS header
to the outer UDP packet */
if (vpninfo->dtls_tos_optname) {
int valid=1;
int tos;
switch(this->data[0] >> 4) {
case 4:
tos = this->data[1];
break;
case 6:
tos = (load_be16(this->data) >> 4) & 0xff;
break;
default:
vpn_progress(vpninfo, PRG_ERR,
_("Unknown packet (len %d) received: %02x %02x %02x %02x...\n"),
this->len, this->data[0], this->data[1], this->data[2], this->data[3]);
valid = 0;
}
/* set the actual value */
if (valid && tos != vpninfo->dtls_tos_current) {
vpn_progress(vpninfo, PRG_DEBUG, _("TOS this: %d, TOS last: %d\n"),
tos, vpninfo->dtls_tos_current);
if (setsockopt(vpninfo->dtls_fd, vpninfo->dtls_tos_proto,
vpninfo->dtls_tos_optname, &tos, sizeof(tos)))
vpn_perror(vpninfo, _("UDP setsockopt"));
else
vpninfo->dtls_tos_current = tos;
}
}
/* One byte of header */
this->cstp.hdr[7] = AC_PKT_DATA;
......
......@@ -87,6 +87,11 @@ OPENCONNECT_5_3 {
openconnect_set_reconnected_handler;
} OPENCONNECT_5_2;
OPENCONNECT_5_4 {
global:
openconnect_set_pass_tos;
} OPENCONNECT_5_3;
OPENCONNECT_PRIVATE {
global: @SYMVER_TIME@ @SYMVER_GETLINE@ @SYMVER_JAVA@ @SYMVER_ASPRINTF@ @SYMVER_VASPRINTF@ @SYMVER_WIN32_STRERROR@
openconnect_fopen_utf8;
......
......@@ -68,6 +68,8 @@ struct openconnect_info *openconnect_vpninfo_new(const char *useragent,
init_pkt_queue(&vpninfo->incoming_queue);
init_pkt_queue(&vpninfo->outgoing_queue);
init_pkt_queue(&vpninfo->oncp_control_queue);
vpninfo->dtls_tos_current = 0;
vpninfo->dtls_pass_tos = 0;
vpninfo->ssl_fd = vpninfo->dtls_fd = -1;
vpninfo->cmd_fd = vpninfo->cmd_fd_write = -1;
vpninfo->tncc_fd = -1;
......@@ -153,8 +155,12 @@ int openconnect_set_protocol(struct openconnect_info *vpninfo, const char *proto
return -EINVAL;
}
void openconnect_set_loglevel(struct openconnect_info *vpninfo,
int level)
void openconnect_set_pass_tos(struct openconnect_info *vpninfo, int enable)
{
vpninfo->dtls_pass_tos = enable;
}
void openconnect_set_loglevel(struct openconnect_info *vpninfo, int level)
{
vpninfo->verbose = level;
}
......@@ -551,6 +557,7 @@ void openconnect_reset_ssl(struct openconnect_info *vpninfo)
free(vpninfo->peer_addr);
vpninfo->peer_addr = NULL;
vpninfo->dtls_tos_optname = 0;
free(vpninfo->ip_info.gateway_addr);
vpninfo->ip_info.gateway_addr = NULL;
......
......@@ -188,6 +188,7 @@ enum {
OPT_HTTP_AUTH,
OPT_LOCAL_HOSTNAME,
OPT_PROTOCOL,
OPT_PASSTOS,
};
#ifdef __sun__
......@@ -227,6 +228,7 @@ static const struct option long_options[] = {
OPTION("base-mtu", 1, OPT_BASEMTU),
OPTION("script", 1, 's'),
OPTION("timestamp", 0, OPT_TIMESTAMP),
OPTION("passtos", 0, OPT_PASSTOS),
OPTION("key-password", 1, 'p'),
OPTION("proxy", 1, 'P'),
OPTION("proxy-auth", 1, OPT_PROXY_AUTH),
......@@ -761,6 +763,7 @@ static void usage(void)
printf(" -l, --syslog %s\n", _("Use syslog for progress messages"));
#endif
printf(" --timestamp %s\n", _("Prepend timestamp to progress messages"));
printf(" --passtos %s\n", _("copy TOS / TCLASS when using DTLS"));
#ifndef _WIN32
printf(" -U, --setuid=USER %s\n", _("Drop privileges after connecting"));
printf(" --csd-user=USER %s\n", _("Drop privileges during CSD execution"));
......@@ -1372,6 +1375,9 @@ int main(int argc, char **argv)
xstrdup("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"));
}
break;
case OPT_PASSTOS:
openconnect_set_pass_tos(vpninfo, 1);
break;
case OPT_TIMESTAMP:
timestamp = 1;
break;
......
......@@ -586,6 +586,10 @@ struct openconnect_info {
int ssl_fd;
int dtls_fd;
int dtls_tos_current;
int dtls_pass_tos;
int dtls_tos_proto, dtls_tos_optname;
int cmd_fd;
int cmd_fd_write;
int got_cancel_cmd;
......@@ -674,7 +678,7 @@ struct openconnect_info {
if ((_v)->verbose >= (lvl)) \
(_v)->progress((_v)->cbdata, lvl, __VA_ARGS__); \
} while(0)
#define vpn_perror(vpninfo, msg) vpn_progress((vpninfo), PRG_ERR, "%s: %s\n", (msg), strerror(errno));
#define vpn_perror(vpninfo, msg) vpn_progress((vpninfo), PRG_ERR, "%s: %s\n", (msg), strerror(errno))
/****************************************************************************/
/* Oh Solaris how we hate thee! */
......
......@@ -21,6 +21,7 @@ openconnect \- Connect to Cisco AnyConnect VPN
.OP \-i,\-\-interface ifname
.OP \-l,\-\-syslog
.OP \-\-timestamp
.OP \-\-passtos
.OP \-U,\-\-setuid user
.OP \-\-csd\-user user
.OP \-m,\-\-mtu mtu
......@@ -194,6 +195,9 @@ Use syslog for progress messages
.B \-\-timestamp
Prepend a timestamp to each progress message
.TP
.B \-\-passtos
Copy TOS / TCLASS of payload packet into DTLS packets.
.TP
.B \-U,\-\-setuid=USER
Drop privileges after connecting, to become user
.I USER
......
......@@ -33,9 +33,12 @@ extern "C" {
#endif
#define OPENCONNECT_API_VERSION_MAJOR 5
#define OPENCONNECT_API_VERSION_MINOR 3
#define OPENCONNECT_API_VERSION_MINOR 4
/*
* API version 5.4:
* - Add openconnect_set_pass_tos()
*
* API version 5.3 (v7.07; 2016-07-11):
* - Add openconnect_set_localname().
* - Add openconnect_override_getaddrinfo().
......@@ -612,8 +615,9 @@ typedef void (*openconnect_protect_socket_vfn) (void *privdata, int fd);
void openconnect_set_protect_socket_handler(struct openconnect_info *vpninfo,
openconnect_protect_socket_vfn protect_socket);
void openconnect_set_loglevel(struct openconnect_info *vpninfo,
int level);
void openconnect_set_loglevel(struct openconnect_info *vpninfo, int level);
void openconnect_set_pass_tos(struct openconnect_info *vpninfo, int enable);
/* Callback for obtaining traffic stats via OC_CMD_STATS.
*/
......
......@@ -908,9 +908,13 @@ int udp_sockaddr(struct openconnect_info *vpninfo, int port)
if (vpninfo->peer_addr->sa_family == AF_INET) {
struct sockaddr_in *sin = (void *)vpninfo->dtls_addr;
sin->sin_port = htons(port);
vpninfo->dtls_tos_proto = IPPROTO_IP;
vpninfo->dtls_tos_optname = IP_TOS;
} else if (vpninfo->peer_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *sin = (void *)vpninfo->dtls_addr;
sin->sin6_port = htons(port);
vpninfo->dtls_tos_proto = IPPROTO_IPV6;
vpninfo->dtls_tos_optname = IPV6_TCLASS;
} else {
vpn_progress(vpninfo, PRG_ERR,
_("Unknown protocol family %d. Cannot create UDP server address\n"),
......@@ -918,6 +922,11 @@ int udp_sockaddr(struct openconnect_info *vpninfo, int port)
return -EINVAL;
}
/* in case DTLS TOS copy is disabled, reset the optname value */
/* so that the copy won't be applied in dtls.c / dtls_mainloop() */
if (!vpninfo->dtls_pass_tos)
vpninfo->dtls_tos_optname = 0;
return 0;
}
......
......@@ -15,6 +15,7 @@
<ul>
<li><b>OpenConnect HEAD</b>
<ul>
<li>Add <tt>--pass-tos</tt> option as in OpenVPN.</li>
<li>Support rôle selection form in Juniper VPN.</li>
<li>Support DER-format certificates, add certificate format torture tests.</li>
<li>For OpenSSL >= 1.0.2, fix certificate validation when only an
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment