diff --git a/dtls.c b/dtls.c index 9a879e48..127e6258 100644 --- a/dtls.c +++ b/dtls.c @@ -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; diff --git a/libopenconnect.map.in b/libopenconnect.map.in index 5ff20f4f..44eea34a 100644 --- a/libopenconnect.map.in +++ b/libopenconnect.map.in @@ -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; diff --git a/library.c b/library.c index b258bbbe..3742f083 100644 --- a/library.c +++ b/library.c @@ -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; diff --git a/main.c b/main.c index b3de6411..8a3a0460 100644 --- a/main.c +++ b/main.c @@ -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; diff --git a/openconnect-internal.h b/openconnect-internal.h index 2295f7ab..5f8b5157 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -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! */ diff --git a/openconnect.8.in b/openconnect.8.in index 475501ae..1968bd07 100644 --- a/openconnect.8.in +++ b/openconnect.8.in @@ -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 diff --git a/openconnect.h b/openconnect.h index 35900fb9..c6217657 100644 --- a/openconnect.h +++ b/openconnect.h @@ -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. */ diff --git a/ssl.c b/ssl.c index 7384a8ec..ce4af6a1 100644 --- a/ssl.c +++ b/ssl.c @@ -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; } diff --git a/www/changelog.xml b/www/changelog.xml index 35c98f19..eaf9d7cc 100644 --- a/www/changelog.xml +++ b/www/changelog.xml @@ -15,6 +15,7 @@