diff --git a/doc/sample.config b/doc/sample.config index 3d50d337..06be160a 100644 --- a/doc/sample.config +++ b/doc/sample.config @@ -174,7 +174,10 @@ ping-leases = false output-buffer = 10 # Set the protocol-defined priority (SO_PRIORITY) for packets to -# be sent. This can be set per user/group or globally. +# be sent. That is a number from 0 to 6 with 0 being the lowest +# priority. Alternatively this can be used to set the IP Type- +# Of-Service, by setting it to a hexadecimal number (e.g., 0x20). +# This can be set per user/group or globally. #net-priority = 3 route = 192.168.1.0/255.255.255.0 diff --git a/src/config.c b/src/config.c index bfb85cee..d7cbb42b 100644 --- a/src/config.c +++ b/src/config.c @@ -178,6 +178,18 @@ unsigned j; exit(1); \ } +#define READ_NUMERIC_HEX(name, s_name) \ + val = get_option(name, &mand); \ + if (val != NULL) { \ + if (val->valType == OPARG_TYPE_NUMERIC) \ + s_name = val->v.longVal; \ + else if (val->valType == OPARG_TYPE_STRING) \ + s_name = strtol(val->v.strVal, NULL, 16); \ + } else if (mand != 0) { \ + fprintf(stderr, "Configuration option %s is mandatory.\n", name); \ + exit(1); \ + } + static int handle_option(const tOptionValue* val) @@ -318,7 +330,15 @@ unsigned prefix = 0; READ_STRING("chroot-dir", config->chroot_dir); READ_NUMERIC("mtu", config->default_mtu); + READ_NUMERIC("net-priority", config->net_priority); + if (config->net_priority == 0) { + READ_NUMERIC_HEX("net-priority", config->net_priority); + config->net_priority = TOS_PACK(config->net_priority); + } else { + config->net_priority++; + } + READ_NUMERIC("output-buffer", config->output_buffer); READ_NUMERIC("rx-data-per-sec", config->rx_per_sec); diff --git a/src/group-config.c b/src/group-config.c index 9cfe6960..522b87f6 100644 --- a/src/group-config.c +++ b/src/group-config.c @@ -89,6 +89,15 @@ static struct cfg_options available_options[] = { s_name = atoi(val->v.strVal); \ } +#define READ_RAW_NUMERIC_HEX(name, s_name) \ + val = optionGetValue(pov, name); \ + if (val != NULL) { \ + if (val->valType == OPARG_TYPE_NUMERIC) \ + s_name = val->v.longVal; \ + else if (val->valType == OPARG_TYPE_STRING) \ + s_name = strtol(val->v.strVal, NULL, 16); \ + } + static int handle_option(const tOptionValue* val) { @@ -153,7 +162,12 @@ unsigned prefix = 0; /* net-priority will contain the actual priority + 1, * to allow having zero as uninitialized. */ READ_RAW_NUMERIC("net-priority", config->net_priority); - config->net_priority++; + if (config->net_priority == 0) { + READ_RAW_NUMERIC_HEX("net-priority", config->net_priority); + config->net_priority = TOS_PACK(config->net_priority); + } else { + config->net_priority++; + } optionUnloadNested(pov); diff --git a/src/ocserv-args.def b/src/ocserv-args.def index 26968b24..274a305d 100644 --- a/src/ocserv-args.def +++ b/src/ocserv-args.def @@ -273,7 +273,9 @@ output-buffer = 10 # Set the protocol-defined priority (SO_PRIORITY) for packets to # be sent. That is a number from 0 to 6 with 0 being the lowest -# priority. This can be set per user/group or globally. +# priority. Alternatively this can be used to set the IP Type- +# Of-Service, by setting it to a hexadecimal number (e.g., 0x20). +# This can be set per user/group or globally. #net-priority = 3 # Routes to be forwarded to the client. If you need the diff --git a/src/vpn.h b/src/vpn.h index 4b0060b2..0521825d 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -228,6 +228,11 @@ const char *human_addr(const struct sockaddr *sa, socklen_t salen, #define SA_IN_P_GENERIC(addr, size) ((size==sizeof(struct sockaddr_in))?SA_IN_U8_P(addr):SA_IN6_U8_P(addr)) #define SA_IN_SIZE(size) ((size==sizeof(struct sockaddr_in))?sizeof(struct in_addr):sizeof(struct in6_addr)) +/* macros */ +#define TOS_PACK(x) (x<<4) +#define TOS_UNPACK(x) (x>>4) +#define IS_TOS(x) ((x&0x0f)==0) + /* Helper structures */ enum option_types { OPTION_NUMERIC, OPTION_STRING, OPTION_BOOLEAN, OPTION_MULTI_LINE }; diff --git a/src/worker-vpn.c b/src/worker-vpn.c index e992075f..d4edd5f3 100644 --- a/src/worker-vpn.c +++ b/src/worker-vpn.c @@ -774,6 +774,36 @@ int max, e, ret; return 0; } +#define TOSCLASS(x) (IPTOS_CLASS_CS##x) + +static void set_net_priority(worker_st *ws, int fd, int priority) +{ +int t; +int ret; +#if defined(IP_TOS) + if (priority != 0 && IS_TOS(priority)) { + t = TOS_UNPACK(priority); + ret = setsockopt( fd, IPPROTO_IP, IP_TOS, &t, sizeof(t)); + if (ret == -1) + oclog(ws, LOG_DEBUG, "setsockopt(IP_TOS) to %x, failed.", (unsigned)t); + + return; + } +#endif + +#ifdef SO_PRIORITY + if (priority != 0 && priority <= 7) { + t = ws->config->net_priority - 1; + ret = setsockopt( fd, SOL_SOCKET, SO_PRIORITY, &t, sizeof(t)); + if (ret == -1) + oclog(ws, LOG_DEBUG, "setsockopt(SO_PRIORITY) to %d, failed.", t); + + return; + } +#endif + return; +} + #define CSTP_DTLS_OVERHEAD 1 #define CSTP_OVERHEAD 8 @@ -991,14 +1021,7 @@ bandwidth_st b_rx; oclog(ws, LOG_DEBUG, "setsockopt(TCP, SO_SNDBUF) to %u, failed.", sndbuf); } -#ifdef SO_PRIORITY - if (ws->config->net_priority != 0) { - l = ws->config->net_priority - 1; - ret = setsockopt( ws->conn_fd, SOL_SOCKET, SO_PRIORITY, &l, sizeof(l)); - if (ret == -1) - oclog(ws, LOG_DEBUG, "setsockopt(TCP, SO_PRIORITY) to %d, failed.", l); - } -#endif + set_net_priority(ws, ws->conn_fd, ws->config->net_priority); if (ws->udp_state != UP_DISABLED) { @@ -1052,14 +1075,7 @@ bandwidth_st b_rx; oclog(ws, LOG_DEBUG, "setsockopt(UDP, SO_SNDBUF) to %u, failed.", sndbuf); } -#ifdef SO_PRIORITY - if (ws->config->net_priority != 0) { - l = ws->config->net_priority - 1; - ret = setsockopt( ws->udp_fd, SOL_SOCKET, SO_PRIORITY, &l, sizeof(l)); - if (ret == -1) - oclog(ws, LOG_DEBUG, "setsockopt(UDP, SO_PRIORITY) to %d, failed.", l); - } -#endif + set_net_priority(ws, ws->udp_fd, ws->config->net_priority); } else dtls_mtu = 0;