curl: support IP Type of Service / Traffic Class: --ip-tos

Add --ip-tos option to the command line tool for setting TOS for IPv4 or
Traffic Class for IPv6.

Closes #13606
This commit is contained in:
Orgad Shaneh 2024-05-12 08:31:15 +03:00 committed by Daniel Stenberg
parent f786fce914
commit 3c20ae08b9
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
8 changed files with 192 additions and 0 deletions

View File

@ -214,6 +214,8 @@ ECHConfigList
ecl
ECONNREFUSED
eCOS
ECT
EF
EFnet
EGD
EHLO
@ -457,6 +459,8 @@ LOGDIR
logfile
lookups
loopback
LOWCOST
LOWDELAY
LPRT
LSB
lseek
@ -488,6 +492,7 @@ Micrium
MicroBlaze
MicroOS
middlebox
MINCOST
mingw
MinGW
MINIX
@ -837,6 +842,7 @@ toolchain
toolchains
toolset
toplevel
TOS
TPF
TrackMemory
transcode

View File

@ -136,6 +136,7 @@ DPAGES = \
include.md \
insecure.md \
interface.md \
ip-tos.md \
ipfs-gateway.md \
ipv4.md \
ipv6.md \

View File

@ -0,0 +1,54 @@
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: ip-tos
Arg: <string>
Help: Set IP Type of Service or Traffic Class
Added: 8.9.0
Category: connection
Protocols: All
Multi: single
See-also:
- tcp-nodelay
Example:
- --ip-tos CS5 $URL
---
# `--ip-tos`
Set Type of Service (TOS) for IPv4 or Traffic Class for IPv6. (Added in 8.9.0).
The values allowed for \<string\> can be a numeric value between 1 and 255
or one of the following:
* CS0
* CS1
* CS2
* CS3
* CS4
* CS5
* CS6
* CS7
* AF11
* AF12
* AF13
* AF21
* AF22
* AF23
* AF31
* AF32
* AF33
* AF41
* AF42
* AF43
* EF
* VOICE-ADMIT
* ECT1
* ECT0
* CE
* LE
* LOWCOST
* LOWDELAY
* THROUGHPUT
* RELIABILITY
* MINCOST

View File

@ -98,6 +98,7 @@
--http3 7.66.0
--http3-only 7.88.0
--ignore-content-length 7.14.1
--ip-tos 8.9.0
--ipfs-gateway 8.4.0
--include (-i) 4.8
--insecure (-k) 7.10

View File

@ -85,6 +85,7 @@ struct OperationConfig {
char *range;
long low_speed_limit;
long low_speed_time;
long ip_tos; /* IP Type of Service */
char *dns_servers; /* dot notation: 1.1.1.1;2.2.2.2 */
char *dns_interface; /* interface name */
char *dns_ipv4_addr; /* dot notation */

View File

@ -328,6 +328,7 @@ typedef enum {
C_TRACE_CONFIG,
C_TRACE_IDS,
C_TRACE_TIME,
C_IP_TOS,
C_UNIX_SOCKET,
C_UPLOAD_FILE,
C_URL,
@ -455,6 +456,7 @@ static const struct LongShort aliases[]= {
{"include", ARG_BOOL, 'i', C_INCLUDE},
{"insecure", ARG_BOOL, 'k', C_INSECURE},
{"interface", ARG_STRG, ' ', C_INTERFACE},
{"ip-tos", ARG_STRG, ' ', C_IP_TOS},
{"ipfs-gateway", ARG_STRG, ' ', C_IPFS_GATEWAY},
{"ipv4", ARG_NONE, '4', C_IPV4},
{"ipv6", ARG_NONE, '6', C_IPV6},
@ -1027,6 +1029,52 @@ static const struct LongShort *single(char letter)
return singles[letter - ' '];
}
struct TOSEntry {
const char *name;
unsigned char value;
};
static const struct TOSEntry tos_entries[] = {
{"AF11", 0x28},
{"AF12", 0x30},
{"AF13", 0x38},
{"AF21", 0x48},
{"AF22", 0x50},
{"AF23", 0x58},
{"AF31", 0x68},
{"AF32", 0x70},
{"AF33", 0x78},
{"AF41", 0x88},
{"AF42", 0x90},
{"AF43", 0x98},
{"CE", 0x03},
{"CS0", 0x00},
{"CS1", 0x20},
{"CS2", 0x40},
{"CS3", 0x60},
{"CS4", 0x80},
{"CS5", 0xa0},
{"CS6", 0xc0},
{"CS7", 0xe0},
{"ECT0", 0x02},
{"ECT1", 0x01},
{"EF", 0xb8},
{"LE", 0x04},
{"LOWCOST", 0x02},
{"LOWDELAY", 0x10},
{"MINCOST", 0x02},
{"RELIABILITY", 0x04},
{"THROUGHPUT", 0x08},
{"VOICE-ADMIT", 0xb0}
};
static int find_tos(const void *a, const void *b)
{
const struct TOSEntry *aa = a;
const struct TOSEntry *bb = b;
return strcmp(aa->name, bb->name);
}
#define MAX_QUERY_LEN 100000 /* larger is not likely to ever work */
static ParameterError url_query(char *nextarg,
struct GlobalConfig *global,
@ -1630,6 +1678,16 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
case C_TCP_NODELAY: /* --tcp-nodelay */
config->tcp_nodelay = toggle;
break;
case C_IP_TOS: { /* --ip-tos */
const struct TOSEntry *entry = bsearch(
&nextarg, tos_entries, sizeof(tos_entries)/sizeof(*tos_entries),
sizeof(*tos_entries), find_tos);
if(entry)
config->ip_tos = entry->value;
else /* numeric tos value */
err = str2unummax(&config->ip_tos, nextarg, 0xFF);
break;
}
case C_PROXY_DIGEST: /* --proxy-digest */
config->proxydigest = toggle;
break;

View File

@ -306,6 +306,9 @@ const struct helptxt helptext[] = {
{" --interface <name>",
"Use network interface",
CURLHELP_CONNECTION},
{" --ip-tos <string>",
"Set IP Type of Service or Traffic Class",
CURLHELP_CONNECTION},
{" --ipfs-gateway <URL>",
"Gateway for IPFS",
CURLHELP_IPFS},

View File

@ -45,6 +45,10 @@
# include <proto/dos.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#define ENABLE_CURLX_PRINTF
/* use our own printf() functions */
#include "curlx.h"
@ -95,6 +99,10 @@
# define O_BINARY 0
#endif
#ifndef SOL_IP
# define SOL_IP IPPROTO_IP
#endif
#define CURL_CA_CERT_ERRORMSG \
"More details here: https://curl.se/docs/sslcerts.html\n\n" \
"curl failed to verify the legitimacy of the server and therefore " \
@ -142,6 +150,55 @@ static bool is_pkcs11_uri(const char *string)
}
}
#ifdef IP_TOS
static int get_address_family(curl_socket_t sockfd)
{
struct sockaddr_storage addr;
socklen_t addrlen = sizeof(addr);
if(getsockname(sockfd, (struct sockaddr *)&addr, &addrlen) == 0)
return addr.ss_family;
return AF_UNSPEC;
}
#endif
#if defined(IP_TOS) || defined(IPV6_TCLASS)
static int sockopt_callback(void *clientp, curl_socket_t curlfd,
curlsocktype purpose)
{
struct OperationConfig *config = (struct OperationConfig *)clientp;
if(purpose != CURLSOCKTYPE_IPCXN)
return CURL_SOCKOPT_OK;
(void)config;
(void)curlfd;
if(config->ip_tos > 0) {
int tos = (int)config->ip_tos;
int result = 0;
switch(get_address_family(curlfd)) {
case AF_INET:
#ifdef IP_TOS
result = setsockopt(curlfd, SOL_IP, IP_TOS,
(const char *)&tos, sizeof(tos));
#endif
break;
case AF_INET6:
#ifdef IPV6_TCLASS
result = setsockopt(curlfd, IPPROTO_IPV6, IPV6_TCLASS,
(const char *)&tos, sizeof(tos));
#endif
break;
}
if(result < 0) {
int error = errno;
warnf(config->global,
"Setting type of service to %d failed with errno %d: %s;\n",
tos, error, strerror(error));
}
}
return CURL_SOCKOPT_OK;
}
#endif
#ifdef __VMS
/*
* get_vms_file_size does what it takes to get the real size of the file
@ -2189,6 +2246,17 @@ static CURLcode single_transfer(struct GlobalConfig *global,
my_setopt_str(curl, CURLOPT_ECH, config->ech_config);
#endif
/* new in 8.9.0 */
if(config->ip_tos > 0) {
#if defined(IP_TOS) || defined(IPV6_TCLASS)
my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_callback);
my_setopt(curl, CURLOPT_SOCKOPTDATA, config);
#else
warnf(config->global,
"Type of service is not supported in this build.");
#endif
}
/* initialize retry vars for loop below */
per->retry_sleep_default = (config->retry_delay) ?
config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */