Skip to content

Commit

Permalink
Add --passtos option to copy TOS/TCLASS from VPN packets
Browse files Browse the repository at this point in the history
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: Ralph Schmieder <ralph.schmieder@gmail.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
rschmied authored and David Woodhouse committed Aug 25, 2016
1 parent 7d3b728 commit 3731692
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 6 deletions.
32 changes: 32 additions & 0 deletions dtls.c
Expand Up @@ -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;

Expand Down
5 changes: 5 additions & 0 deletions libopenconnect.map.in
Expand Up @@ -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;
Expand Down
11 changes: 9 additions & 2 deletions library.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;

Expand Down
6 changes: 6 additions & 0 deletions main.c
Expand Up @@ -188,6 +188,7 @@ enum {
OPT_HTTP_AUTH,
OPT_LOCAL_HOSTNAME,
OPT_PROTOCOL,
OPT_PASSTOS,
};

#ifdef __sun__
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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"));
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 5 additions & 1 deletion openconnect-internal.h
Expand Up @@ -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;
Expand Down Expand Up @@ -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! */
Expand Down
4 changes: 4 additions & 0 deletions openconnect.8.in
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
10 changes: 7 additions & 3 deletions openconnect.h
Expand Up @@ -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().
Expand Down Expand Up @@ -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.
*/
Expand Down
9 changes: 9 additions & 0 deletions ssl.c
Expand Up @@ -908,16 +908,25 @@ 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"),
vpninfo->peer_addr->sa_family);
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;
}

Expand Down
1 change: 1 addition & 0 deletions www/changelog.xml
Expand Up @@ -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
Expand Down

0 comments on commit 3731692

Please sign in to comment.