I originally submitted this as a patch for openssh-unix-dev as:
https://bugzilla.mindrot.org/show_bug.cgi?id=1733 about 8 months ago, but figured it would be quicker to get it in upstream. The patch has 4 main changes: (1) add new options to define the DSCP/Class-Selector values; (2) add name-to-value mappings for the DSCP/Class-Selector values; (3) add a parameter to keywords[] to specify whether an option can be user-specified (QoS bits usually should be set site-wide only by the site's network administrator); (4) rather than passing in the interactive/non-interactive to packet_set_tos(), just pass in the desired QoS marking instead. We've been using the patch in the astlinux project and it works fine. Revised with man page updates as per Han's comment. Signed-off-by: Philip Prindeville <[email protected]> ---- Index: ipclass.h =================================================================== RCS file: ipclass.h diff -N -u -p ipclass.h --- /dev/null 21 Jun 2010 01:27:58 -0000 +++ ipclass.h 21 Jun 2010 07:27:56 -0000 @@ -0,0 +1,20 @@ +/* + * Temporarily needed file until glibc 2.12 becomes ubiquitous. + */ +#ifndef __IPCLASS_H__ +#define __IPCLASS_H__ + +/* in glibc 2.12 */ +#ifndef IPTOS_CLASS_CS0 +#define IPTOS_CLASS_CS0 0x00 +#define IPTOS_CLASS_CS1 0x20 +#define IPTOS_CLASS_CS2 0x40 +#define IPTOS_CLASS_CS3 0x60 +#define IPTOS_CLASS_CS4 0x80 +#define IPTOS_CLASS_CS5 0xa0 +#define IPTOS_CLASS_CS6 0xc0 +#define IPTOS_CLASS_CS7 0xe0 +#endif + +#endif /* __IPCLASS_H__ */ + Index: packet.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/packet.c,v retrieving revision 1.166 diff -N -u -p packet.c --- packet.c 27 Jun 2009 09:29:06 -0000 1.166 +++ packet.c 21 Jun 2010 07:27:56 -0000 @@ -74,6 +74,7 @@ #include "misc.h" #include "ssh.h" #include "roaming.h" +#include "readconf.h" #ifdef PACKET_DEBUG #define DBG(x) x @@ -1716,10 +1717,8 @@ packet_not_very_much_data_to_write(void) } static void -packet_set_tos(int interactive) +packet_set_tos(int tos) { - int tos = interactive ? IPTOS_LOWDELAY : IPTOS_THROUGHPUT; - if (!packet_connection_is_on_socket() || !packet_connection_is_ipv4()) return; @@ -1732,7 +1731,7 @@ packet_set_tos(int interactive) /* Informs that the current session is interactive. Sets IP flags for that. */ void -packet_set_interactive(int interactive) +packet_set_interactive(int interactive, int qos[2]) { if (active_state->set_interactive_called) return; @@ -1745,7 +1744,7 @@ packet_set_interactive(int interactive) if (!packet_connection_is_on_socket()) return; set_nodelay(active_state->connection_in); - packet_set_tos(interactive); + packet_set_tos((u_char) (interactive ? qos[1] : qos[0])); } /* Returns true if the current connection is interactive. */ Index: packet.h =================================================================== RCS file: /cvs/src/usr.bin/ssh/packet.h,v retrieving revision 1.52 diff -N -u -p packet.h --- packet.h 27 Jun 2009 09:29:06 -0000 1.52 +++ packet.h 21 Jun 2010 07:27:56 -0000 @@ -31,7 +31,7 @@ u_int packet_get_encryption_key(u_char *); void packet_set_protocol_flags(u_int); u_int packet_get_protocol_flags(void); void packet_start_compression(int); -void packet_set_interactive(int); +void packet_set_interactive(int, int [2]); int packet_is_interactive(void); void packet_set_server(void); void packet_set_authenticated(void); Index: readconf.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/readconf.c,v retrieving revision 1.184 diff -N -u -p readconf.c --- readconf.c 16 May 2010 12:55:51 -0000 1.184 +++ readconf.c 21 Jun 2010 07:27:56 -0000 @@ -40,6 +40,12 @@ #include "kex.h" #include "mac.h" +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#ifndef IPTOS_CLASS_CS0 +#include "ipclass.h" +#endif + /* Format of the configuration file: # Configuration data is parsed as follows: @@ -128,6 +134,7 @@ typedef enum { oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, + oUseQoS, oDeprecated, oUnsupported } OpCodes; @@ -135,107 +142,109 @@ typedef enum { static struct { const char *name; + int restricted; OpCodes opcode; } keywords[] = { - { "forwardagent", oForwardAgent }, - { "forwardx11", oForwardX11 }, - { "forwardx11trusted", oForwardX11Trusted }, - { "exitonforwardfailure", oExitOnForwardFailure }, - { "xauthlocation", oXAuthLocation }, - { "gatewayports", oGatewayPorts }, - { "useprivilegedport", oUsePrivilegedPort }, - { "rhostsauthentication", oDeprecated }, - { "passwordauthentication", oPasswordAuthentication }, - { "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, - { "kbdinteractivedevices", oKbdInteractiveDevices }, - { "rsaauthentication", oRSAAuthentication }, - { "pubkeyauthentication", oPubkeyAuthentication }, - { "dsaauthentication", oPubkeyAuthentication }, /* alias */ - { "rhostsrsaauthentication", oRhostsRSAAuthentication }, - { "hostbasedauthentication", oHostbasedAuthentication }, - { "challengeresponseauthentication", oChallengeResponseAuthentication }, - { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */ - { "tisauthentication", oChallengeResponseAuthentication }, /* alias */ - { "kerberosauthentication", oUnsupported }, - { "kerberostgtpassing", oUnsupported }, - { "afstokenpassing", oUnsupported }, + { "forwardagent", 0, oForwardAgent }, + { "forwardx11", 0, oForwardX11 }, + { "forwardx11trusted", 0, oForwardX11Trusted }, + { "exitonforwardfailure", 0, oExitOnForwardFailure }, + { "xauthlocation", 0, oXAuthLocation }, + { "gatewayports", 0, oGatewayPorts }, + { "useprivilegedport", 0, oUsePrivilegedPort }, + { "rhostsauthentication", 0, oDeprecated }, + { "passwordauthentication", 0, oPasswordAuthentication }, + { "kbdinteractiveauthentication", 0, oKbdInteractiveAuthentication }, + { "kbdinteractivedevices", 0, oKbdInteractiveDevices }, + { "rsaauthentication", 0, oRSAAuthentication }, + { "pubkeyauthentication", 0, oPubkeyAuthentication }, + { "dsaauthentication", 0, oPubkeyAuthentication }, /* alias */ + { "rhostsrsaauthentication", 0, oRhostsRSAAuthentication }, + { "hostbasedauthentication", 0, oHostbasedAuthentication }, + { "challengeresponseauthentication", 0, oChallengeResponseAuthentication }, + { "skeyauthentication", 0, oChallengeResponseAuthentication }, /* alias */ + { "tisauthentication", 0, oChallengeResponseAuthentication }, /* alias */ + { "kerberosauthentication", 0, oUnsupported }, + { "kerberostgtpassing", 0, oUnsupported }, + { "afstokenpassing", 0, oUnsupported }, #if defined(GSSAPI) - { "gssapiauthentication", oGssAuthentication }, - { "gssapidelegatecredentials", oGssDelegateCreds }, + { "gssapiauthentication", 0, oGssAuthentication }, + { "gssapidelegatecredentials", 0, oGssDelegateCreds }, #else - { "gssapiauthentication", oUnsupported }, - { "gssapidelegatecredentials", oUnsupported }, + { "gssapiauthentication", 0, oUnsupported }, + { "gssapidelegatecredentials", 0, oUnsupported }, #endif - { "fallbacktorsh", oDeprecated }, - { "usersh", oDeprecated }, - { "identityfile", oIdentityFile }, - { "identityfile2", oIdentityFile }, /* obsolete */ - { "identitiesonly", oIdentitiesOnly }, - { "hostname", oHostName }, - { "hostkeyalias", oHostKeyAlias }, - { "proxycommand", oProxyCommand }, - { "port", oPort }, - { "cipher", oCipher }, - { "ciphers", oCiphers }, - { "macs", oMacs }, - { "protocol", oProtocol }, - { "remoteforward", oRemoteForward }, - { "localforward", oLocalForward }, - { "user", oUser }, - { "host", oHost }, - { "escapechar", oEscapeChar }, - { "globalknownhostsfile", oGlobalKnownHostsFile }, - { "globalknownhostsfile2", oGlobalKnownHostsFile2 }, /* obsolete */ - { "userknownhostsfile", oUserKnownHostsFile }, - { "userknownhostsfile2", oUserKnownHostsFile2 }, /* obsolete */ - { "connectionattempts", oConnectionAttempts }, - { "batchmode", oBatchMode }, - { "checkhostip", oCheckHostIP }, - { "stricthostkeychecking", oStrictHostKeyChecking }, - { "compression", oCompression }, - { "compressionlevel", oCompressionLevel }, - { "tcpkeepalive", oTCPKeepAlive }, - { "keepalive", oTCPKeepAlive }, /* obsolete */ - { "numberofpasswordprompts", oNumberOfPasswordPrompts }, - { "loglevel", oLogLevel }, - { "dynamicforward", oDynamicForward }, - { "preferredauthentications", oPreferredAuthentications }, - { "hostkeyalgorithms", oHostKeyAlgorithms }, - { "bindaddress", oBindAddress }, + { "fallbacktorsh", 0, oDeprecated }, + { "usersh", 0, oDeprecated }, + { "identityfile", 0, oIdentityFile }, + { "identityfile2", 0, oIdentityFile }, /* obsolete */ + { "identitiesonly", 0, oIdentitiesOnly }, + { "hostname", 0, oHostName }, + { "hostkeyalias", 0, oHostKeyAlias }, + { "proxycommand", 0, oProxyCommand }, + { "port", 0, oPort }, + { "cipher", 0, oCipher }, + { "ciphers", 0, oCiphers }, + { "macs", 0, oMacs }, + { "protocol", 0, oProtocol }, + { "remoteforward", 0, oRemoteForward }, + { "localforward", 0, oLocalForward }, + { "user", 0, oUser }, + { "host", 0, oHost }, + { "escapechar", 0, oEscapeChar }, + { "globalknownhostsfile", 0, oGlobalKnownHostsFile }, + { "globalknownhostsfile2", 0, oGlobalKnownHostsFile2 }, /* obsolete */ + { "userknownhostsfile", 0, oUserKnownHostsFile }, + { "userknownhostsfile2", 0, oUserKnownHostsFile2 }, /* obsolete */ + { "connectionattempts", 0, oConnectionAttempts }, + { "batchmode", 0, oBatchMode }, + { "checkhostip", 0, oCheckHostIP }, + { "stricthostkeychecking", 0, oStrictHostKeyChecking }, + { "compression", 0, oCompression }, + { "compressionlevel", 0, oCompressionLevel }, + { "tcpkeepalive", 0, oTCPKeepAlive }, + { "keepalive", 0, oTCPKeepAlive }, /* obsolete */ + { "numberofpasswordprompts", 0, oNumberOfPasswordPrompts }, + { "loglevel", 0, oLogLevel }, + { "dynamicforward", 0, oDynamicForward }, + { "preferredauthentications", 0, oPreferredAuthentications }, + { "hostkeyalgorithms", 0, oHostKeyAlgorithms }, + { "bindaddress", 0, oBindAddress }, #ifdef ENABLE_PKCS11 - { "smartcarddevice", oPKCS11Provider }, - { "pkcs11provider", oPKCS11Provider }, + { "smartcarddevice", 0, oPKCS11Provider }, + { "pkcs11provider", 0, oPKCS11Provider }, #else - { "smartcarddevice", oUnsupported }, - { "pkcs11provider", oUnsupported }, + { "smartcarddevice", 0, oUnsupported }, + { "pkcs11provider", 0, oUnsupported }, #endif - { "clearallforwardings", oClearAllForwardings }, - { "enablesshkeysign", oEnableSSHKeysign }, - { "verifyhostkeydns", oVerifyHostKeyDNS }, - { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, - { "rekeylimit", oRekeyLimit }, - { "connecttimeout", oConnectTimeout }, - { "addressfamily", oAddressFamily }, - { "serveraliveinterval", oServerAliveInterval }, - { "serveralivecountmax", oServerAliveCountMax }, - { "sendenv", oSendEnv }, - { "controlpath", oControlPath }, - { "controlmaster", oControlMaster }, - { "hashknownhosts", oHashKnownHosts }, - { "tunnel", oTunnel }, - { "tunneldevice", oTunnelDevice }, - { "localcommand", oLocalCommand }, - { "permitlocalcommand", oPermitLocalCommand }, - { "visualhostkey", oVisualHostKey }, - { "useroaming", oUseRoaming }, + { "clearallforwardings", 0, oClearAllForwardings }, + { "enablesshkeysign", 0, oEnableSSHKeysign }, + { "verifyhostkeydns", 0, oVerifyHostKeyDNS }, + { "nohostauthenticationforlocalhost", 0, oNoHostAuthenticationForLocalhost }, + { "rekeylimit", 0, oRekeyLimit }, + { "connecttimeout", 0, oConnectTimeout }, + { "addressfamily", 0, oAddressFamily }, + { "serveraliveinterval", 0, oServerAliveInterval }, + { "serveralivecountmax", 0, oServerAliveCountMax }, + { "sendenv", 0, oSendEnv }, + { "controlpath", 0, oControlPath }, + { "controlmaster", 0, oControlMaster }, + { "hashknownhosts", 0, oHashKnownHosts }, + { "tunnel", 0, oTunnel }, + { "tunneldevice", 0, oTunnelDevice }, + { "localcommand", 0, oLocalCommand }, + { "permitlocalcommand", 0, oPermitLocalCommand }, + { "visualhostkey", 0, oVisualHostKey }, + { "useroaming", 0, oUseRoaming }, + { "useqos", 1, oUseQoS}, #ifdef JPAKE - { "zeroknowledgepasswordauthentication", + { "zeroknowledgepasswordauthentication", 0, oZeroKnowledgePasswordAuthentication }, #else - { "zeroknowledgepasswordauthentication", oUnsupported }, + { "zeroknowledgepasswordauthentication", 0, oUnsupported }, #endif - { NULL, oBadOption } + { NULL, 0, oBadOption } }; /* @@ -306,19 +315,69 @@ clear_forwardings(Options *options) */ static OpCodes -parse_token(const char *cp, const char *filename, int linenum) +parse_token(const char *cp, const char *filename, int linenum, int *restricted) { u_int i; for (i = 0; keywords[i].name; i++) - if (strcasecmp(cp, keywords[i].name) == 0) + if (strcasecmp(cp, keywords[i].name) == 0) { + *restricted= keywords[i].restricted; return keywords[i].opcode; + } error("%s: line %d: Bad configuration option: %s", filename, linenum, cp); return oBadOption; } +struct { + const char *name; + int value; +} qos[] = { + { "cs0", IPTOS_CLASS_CS0 }, + { "cs1", IPTOS_CLASS_CS1 }, + { "cs2", IPTOS_CLASS_CS2 }, + { "cs3", IPTOS_CLASS_CS3 }, + { "cs4", IPTOS_CLASS_CS4 }, + { "cs5", IPTOS_CLASS_CS5 }, + { "cs6", IPTOS_CLASS_CS6 }, + { "cs7", IPTOS_CLASS_CS7 }, + { "af11", IPTOS_DSCP_AF11 }, + { "af12", IPTOS_DSCP_AF12 }, + { "af13", IPTOS_DSCP_AF13 }, + { "af21", IPTOS_DSCP_AF21 }, + { "af22", IPTOS_DSCP_AF22 }, + { "af23", IPTOS_DSCP_AF23 }, + { "af31", IPTOS_DSCP_AF31 }, + { "af32", IPTOS_DSCP_AF32 }, + { "af33", IPTOS_DSCP_AF33 }, + { "af41", IPTOS_DSCP_AF41 }, + { "af42", IPTOS_DSCP_AF42 }, + { "af43", IPTOS_DSCP_AF43 }, + { "ef", IPTOS_DSCP_EF }, + { "lowdelay", IPTOS_LOWDELAY }, + { "throughput", IPTOS_THROUGHPUT }, + { "reliability", IPTOS_RELIABILITY }, +#ifdef IPTOS_LOWCOST + { "lowcost", IPTOS_LOWCOST }, +#endif +#ifdef IPTOS_MINCOST + { "mincost", IPTOS_MINCOST }, +#endif + { "none", IPTOS_CLASS_CS0 }, + { NULL, -1 }, +}; + +static int parse_qos(const char *cp) +{ + u_int i; + + for (i = 0; qos[i].name; i++) + if (strcasecmp(cp, qos[i].name) == 0) + return qos[i].value; + return -1; +} + /* * Processes a single option line as used in the configuration files. This * only sets those values that have not already been set. @@ -328,10 +387,10 @@ parse_token(const char *cp, const char *filename, int int process_config_line(Options *options, const char *host, char *line, const char *filename, int linenum, - int *activep) + int *activep, int systemwide) { char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256]; - int opcode, *intptr, value, value2, scale; + int opcode, *intptr, value, value2, scale, restricted; LogLevel *log_level_ptr; long long orig, val64; size_t len; @@ -354,8 +413,12 @@ process_config_line(Options *options, const char *host if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') return 0; - opcode = parse_token(keyword, filename, linenum); + opcode = parse_token(keyword, filename, linenum, &restricted); + if (restricted && !systemwide) { + fatal("%s line %d: not permitted in user profile.", filename, linenum); + } + switch (opcode) { case oBadOption: /* don't panic, but count bad options */ @@ -917,6 +980,27 @@ parse_int: intptr = &options->use_roaming; goto parse_flag; + case oUseQoS: + arg = strdelim(&s); + if (arg == NULL || *arg == '\0') + fatal("%.200s line %d: Missing non-interactive QoS argument.", + filename, linenum); + + arg2 = strdelim(&s); + if (arg2 == NULL || *arg2 == '\0') + fatal("%.200s line %d: Missing interactive QoS argument.", + filename, linenum); + + value = parse_qos(arg); + value2 = parse_qos(arg2); + if (value == -1 || value2 == -1) + fatal("%.200s line %d: Bad QoS argument.", + filename, linenum); + + options->use_qos[0] = value; + options->use_qos[1] = value2; + break; + case oDeprecated: debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); @@ -948,7 +1032,7 @@ parse_int: int read_config_file(const char *filename, const char *host, Options *options, - int checkperm) + int checkperm, int systemwide) { FILE *f; char line[1024]; @@ -979,7 +1063,7 @@ read_config_file(const char *filename, const char *hos while (fgets(line, sizeof(line), f)) { /* Update line number counter. */ linenum++; - if (process_config_line(options, host, line, filename, linenum, &active) != 0) + if (process_config_line(options, host, line, filename, linenum, &active, systemwide) != 0) bad_options++; } fclose(f); @@ -1067,6 +1151,8 @@ initialize_options(Options * options) options->local_command = NULL; options->permit_local_command = -1; options->use_roaming = -1; + options->use_qos[0] = -1; + options->use_qos[1] = -1; options->visual_host_key = -1; options->zero_knowledge_password_authentication = -1; } @@ -1215,6 +1301,10 @@ fill_default_options(Options * options) /* options->hostname will be set in the main program if appropriate */ /* options->host_key_alias should not be set by default */ /* options->preferred_authentications will be set in ssh */ + if (options->use_qos[0] == -1) + options->use_qos[0] = IPTOS_THROUGHPUT; + if (options->use_qos[1] == -1) + options->use_qos[1] = IPTOS_LOWDELAY; } /* Index: readconf.h =================================================================== RCS file: /cvs/src/usr.bin/ssh/readconf.h,v retrieving revision 1.83 diff -N -u -p readconf.h --- readconf.h 16 May 2010 12:55:51 -0000 1.83 +++ readconf.h 21 Jun 2010 07:27:56 -0000 @@ -126,6 +126,8 @@ typedef struct { int use_roaming; + int use_qos[2]; + } Options; #define SSHCTL_MASTER_NO 0 @@ -136,11 +138,11 @@ typedef struct { void initialize_options(Options *); void fill_default_options(Options *); -int read_config_file(const char *, const char *, Options *, int); +int read_config_file(const char *, const char *, Options *, int, int); int parse_forward(Forward *, const char *, int, int); int -process_config_line(Options *, const char *, char *, const char *, int, int *); +process_config_line(Options *, const char *, char *, const char *, int, int *, int); void add_local_forward(Options *, const Forward *); void add_remote_forward(Options *, const Forward *); Index: servconf.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/servconf.c,v retrieving revision 1.208 diff -N -u -p servconf.c --- servconf.c 7 May 2010 11:30:29 -0000 1.208 +++ servconf.c 21 Jun 2010 07:27:56 -0000 @@ -40,6 +40,13 @@ #include "channels.h" #include "groupaccess.h" +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#ifndef IPTOS_CLASS_CS0 +#include "ipclass.h" +#endif + static void add_listen_addr(ServerOptions *, char *, int); static void add_one_listen_addr(ServerOptions *, char *, int); @@ -125,6 +132,8 @@ initialize_server_options(ServerOptions *options) options->revoked_keys_file = NULL; options->trusted_user_ca_keys = NULL; options->authorized_principals_file = NULL; + options->use_qos[0] = -1; + options->use_qos[1] = -1; } void @@ -254,6 +263,10 @@ fill_default_server_options(ServerOptions *options) options->permit_tun = SSH_TUNMODE_NO; if (options->zero_knowledge_password_authentication == -1) options->zero_knowledge_password_authentication = 0; + if (options->use_qos[0] == -1) + options->use_qos[0] = IPTOS_THROUGHPUT; + if (options->use_qos[1] == -1) + options->use_qos[1] = IPTOS_LOWDELAY; /* Turn privilege separation on by default */ if (use_privsep == -1) @@ -287,6 +300,7 @@ typedef enum { sUsePrivilegeSeparation, sAllowAgentForwarding, sZeroKnowledgePasswordAuthentication, sHostCertificate, sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, + sUseQoS, sDeprecated, sUnsupported } ServerOpCodes; @@ -397,6 +411,7 @@ static struct { { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_GLOBAL }, + { "useqos", sUseQoS, SSHCFG_ALL }, { NULL, sBadOption, 0 } }; @@ -432,6 +447,54 @@ parse_token(const char *cp, const char *filename, return sBadOption; } +struct { + const char *name; + int value; +} qos[] = { + { "cs0", IPTOS_CLASS_CS0 }, + { "cs1", IPTOS_CLASS_CS1 }, + { "cs2", IPTOS_CLASS_CS2 }, + { "cs3", IPTOS_CLASS_CS3 }, + { "cs4", IPTOS_CLASS_CS4 }, + { "cs5", IPTOS_CLASS_CS5 }, + { "cs6", IPTOS_CLASS_CS6 }, + { "cs7", IPTOS_CLASS_CS7 }, + { "af11", IPTOS_DSCP_AF11 }, + { "af12", IPTOS_DSCP_AF12 }, + { "af13", IPTOS_DSCP_AF13 }, + { "af21", IPTOS_DSCP_AF21 }, + { "af22", IPTOS_DSCP_AF22 }, + { "af23", IPTOS_DSCP_AF23 }, + { "af31", IPTOS_DSCP_AF31 }, + { "af32", IPTOS_DSCP_AF32 }, + { "af33", IPTOS_DSCP_AF33 }, + { "af41", IPTOS_DSCP_AF41 }, + { "af42", IPTOS_DSCP_AF42 }, + { "af43", IPTOS_DSCP_AF43 }, + { "ef", IPTOS_DSCP_EF }, + { "lowdelay", IPTOS_LOWDELAY }, + { "throughput", IPTOS_THROUGHPUT }, + { "reliability", IPTOS_RELIABILITY }, +#ifdef IPTOS_LOWCOST + { "lowcost", IPTOS_LOWCOST }, +#endif +#ifdef IPTOS_MINCOST + { "mincost", IPTOS_MINCOST }, +#endif + { "none", IPTOS_CLASS_CS0 }, + { NULL, -1 }, +}; + +static int parse_qos(const char *cp) +{ + u_int i; + + for (i = 0; qos[i].name; i++) + if (strcasecmp(cp, qos[i].name) == 0) + return qos[i].value; + return -1; +} + char * derelativise_path(const char *path) { @@ -625,8 +688,8 @@ process_server_config_line(ServerOptions *options, cha const char *filename, int linenum, int *activep, const char *user, const char *host, const char *address) { - char *cp, **charptr, *arg, *p; - int cmdline = 0, *intptr, value, n; + char *cp, **charptr, *arg, *arg2, *p; + int cmdline = 0, *intptr, value, value2, n; SyslogFacility *log_facility_ptr; LogLevel *log_level_ptr; ServerOpCodes opcode; @@ -1307,6 +1370,27 @@ process_server_config_line(ServerOptions *options, cha case sRevokedKeys: charptr = &options->revoked_keys_file; goto parse_filename; + + case sUseQoS: + arg = strdelim(&cp); + if (arg == NULL || *arg == '\0') + fatal("%.200s line %d: Missing non-interactive QoS argument.", + filename, linenum); + + arg2 = strdelim(&cp); + if (arg2 == NULL || *arg2 == '\0') + fatal("%.200s line %d: Missing interactive QoS argument.", + filename, linenum); + + value = parse_qos(arg); + value2 = parse_qos(arg2); + if (value == -1 || value2 == -1) + fatal("%.200s line %d: Bad QoS argument.", + filename, linenum); + + options->use_qos[0] = value; + options->use_qos[1] = value2; + break; case sDeprecated: logit("%s line %d: Deprecated option %s", Index: servconf.h =================================================================== RCS file: /cvs/src/usr.bin/ssh/servconf.h,v retrieving revision 1.93 diff -N -u -p servconf.h --- servconf.h 7 May 2010 11:30:30 -0000 1.93 +++ servconf.h 21 Jun 2010 07:27:56 -0000 @@ -155,6 +155,8 @@ typedef struct { char *revoked_keys_file; char *trusted_user_ca_keys; char *authorized_principals_file; + + int use_qos[2]; } ServerOptions; void initialize_server_options(ServerOptions *); Index: session.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/session.c,v retrieving revision 1.254 diff -N -u -p session.c --- session.c 18 Jun 2010 03:16:03 -0000 1.254 +++ session.c 21 Jun 2010 07:27:56 -0000 @@ -587,7 +587,7 @@ do_exec_no_pty(Session *s, const char *command) s->pid = pid; /* Set interactive/non-interactive mode. */ - packet_set_interactive(s->display != NULL); + packet_set_interactive(s->display != NULL, options.use_qos); #ifdef USE_PIPES /* We are the parent. Close the child sides of the pipes. */ @@ -715,7 +715,7 @@ do_exec_pty(Session *s, const char *command) /* Enter interactive session. */ s->ptymaster = ptymaster; - packet_set_interactive(1); + packet_set_interactive(1, options.use_qos); if (compat20) { session_set_fds(s, ptyfd, fdout, -1, 1); } else { Index: ssh-keysign.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/ssh-keysign.c,v retrieving revision 1.30 diff -N -u -p ssh-keysign.c --- ssh-keysign.c 13 Jan 2010 01:20:20 -0000 1.30 +++ ssh-keysign.c 21 Jun 2010 07:27:56 -0000 @@ -176,7 +176,7 @@ main(int argc, char **argv) /* verify that ssh-keysign is enabled by the admin */ initialize_options(&options); - (void)read_config_file(_PATH_HOST_CONFIG_FILE, "", &options, 0); + (void)read_config_file(_PATH_HOST_CONFIG_FILE, "", &options, 0, 1); fill_default_options(&options); if (options.enable_ssh_keysign != 1) fatal("ssh-keysign not enabled in %s", Index: ssh.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/ssh.c,v retrieving revision 1.338 diff -N -u -p ssh.c --- ssh.c 16 May 2010 12:55:51 -0000 1.338 +++ ssh.c 21 Jun 2010 07:27:56 -0000 @@ -522,7 +522,7 @@ main(int ac, char **av) dummy = 1; line = xstrdup(optarg); if (process_config_line(&options, host ? host : "", - line, "command-line", 0, &dummy) != 0) + line, "command-line", 0, &dummy, 0) != 0) exit(255); xfree(line); break; @@ -632,18 +632,18 @@ main(int ac, char **av) * file if the user specifies a config file on the command line. */ if (config != NULL) { - if (!read_config_file(config, host, &options, 0)) + if (!read_config_file(config, host, &options, 0, 0)) fatal("Can't open user config file %.100s: " "%.100s", config, strerror(errno)); } else { r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_USER_CONFFILE); if (r > 0 && (size_t)r < sizeof(buf)) - (void)read_config_file(buf, host, &options, 1); + (void)read_config_file(buf, host, &options, 1, 0); /* Read systemwide configuration file after use config. */ (void)read_config_file(_PATH_HOST_CONFIG_FILE, host, - &options, 0); + &options, 0, 1); } /* Fill configuration defaults. */ @@ -1095,7 +1095,7 @@ ssh_session(void) } } /* Tell the packet module whether this is an interactive session. */ - packet_set_interactive(interactive); + packet_set_interactive(interactive, options.use_qos); /* Request authentication agent forwarding if appropriate. */ check_agent_present(); @@ -1192,7 +1192,7 @@ ssh_session2_setup(int id, int success, void *arg) client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"), NULL, fileno(stdin), &command, environ); - packet_set_interactive(interactive); + packet_set_interactive(interactive, options.use_qos); } /* open new channel for a session */ Index: ssh_config =================================================================== RCS file: /cvs/src/usr.bin/ssh/ssh_config,v retrieving revision 1.26 diff -N -u -p ssh_config --- ssh_config 11 Jan 2010 01:39:46 -0000 1.26 +++ ssh_config 21 Jun 2010 07:27:56 -0000 @@ -45,3 +45,4 @@ # PermitLocalCommand no # VisualHostKey no # ProxyCommand ssh -q -W %h:%p gateway.example.com +# UseQoS throughput lowdelay Index: ssh_config.5 =================================================================== RCS file: /cvs/src/usr.bin/ssh/ssh_config.5,v retrieving revision 1.133 diff -N -u -p ssh_config.5 --- ssh_config.5 16 Apr 2010 06:45:01 -0000 1.133 +++ ssh_config.5 21 Jun 2010 07:27:56 -0000 @@ -1050,6 +1050,38 @@ Specifies the user to log in as. This can be useful when a different user name is used on different machines. This saves the trouble of having to remember to give the user name on the command line. +.It Cm UseQoS +Specifies how +.Xr ssh 1 +applies IP TOS (type of service) marking to traffic. It takes two values, +one for non-interactive traffic (\c +.Xr scp 1 +or +.Xr ssh 1 +being run with a command), and another for interactive traffic. +Values may be +.Dq cs0 , +.Dq cs1 , +\&... +.Dq cs7 , +.Dq af11 , +.Dq af12 , +\&... +.Dq af43 , +.Dq ef , +.Dq lowdelay , +.Dq throughput , +etc. The default is +.Dq cs0 +for both. In an RFC-4594 environment, +.Dq cs2 +and +.Dq af41 +would be used, respectively. Legacy behavior would +.Dq throughput +and +.Dq lowdelay , +respectively. .It Cm UserKnownHostsFile Specifies a file to use for the user host key database instead of Index: sshd_config =================================================================== RCS file: /cvs/src/usr.bin/ssh/sshd_config,v retrieving revision 1.81 diff -N -u -p sshd_config --- sshd_config 8 Oct 2009 14:03:41 -0000 1.81 +++ sshd_config 21 Jun 2010 07:27:56 -0000 @@ -97,6 +97,9 @@ # override default of no subsystems Subsystem sftp /usr/libexec/sftp-server +# traditional ToS (deprecated: consider using af12 and cs2) +#UseQoS throughput lowdelay + # Example of overriding settings on a per-user basis #Match User anoncvs # X11Forwarding no Index: sshd_config.5 =================================================================== RCS file: /cvs/src/usr.bin/ssh/sshd_config.5,v retrieving revision 1.122 diff -N -u -p sshd_config.5 --- sshd_config.5 7 May 2010 12:49:17 -0000 1.122 +++ sshd_config.5 21 Jun 2010 07:27:58 -0000 @@ -985,6 +985,38 @@ The goal of privilege separation is to prevent privile escalation by containing any corruption within the unprivileged processes. The default is .Dq yes . +.It Cm UseQoS +Specifies how +.Xr sshd 8 +applies IP TOS (type of service) marking to traffic. It takes two values, +one for non-interactive traffic (\c +.Xr scp 1 +or +.Xr ssh 1 +being run with a command), and another for interactive traffic. +Values may be +.Dq cs0 , +.Dq cs1 , +\&... +.Dq cs7 , +.Dq af11 , +.Dq af12 , +\&... +.Dq af43 , +.Dq ef , +.Dq lowdelay , +.Dq throughput , +etc. The default is +.Dq cs0 +for both. In an RFC-4594 environment, +.Dq cs2 +and +.Dq af41 +would be used, respectively. Legacy behavior would +.Dq throughput +and +.Dq lowdelay , +respectively. .It Cm X11DisplayOffset Specifies the first display number available for .Xr sshd 8 Ns 's
