diff --git a/crypto/openssh/README.hpn b/crypto/openssh/README.hpn new file mode 100644 index 000000000000..674827fb6b4d --- /dev/null +++ b/crypto/openssh/README.hpn @@ -0,0 +1,120 @@ +Notes: + +NONE CIPHER: + To use the NONE option you must have the NoneEnabled switch set on the server + and you MUST have *both* NoneEnabled and NoneSwitch set to yes on the client. + The NONE feature works with ALL ssh subsystems (as far as we can tell) + as long as there is no tty allocated. + If a user uses the -T switch to prevent a tty being created the NONE cipher + will be disabled. + + +PERFORMANCE: + The performance increase will only be as good as the network and TCP stack + tuning on the reciever side of the connection allows. As a rule of thumb a + user will need at least 10Mb/s connection with a 100ms RTT to see a doubling + of performance. + The HPN-SSH home page http://www.psc.edu/networking/projects/hpn-ssh + describes this in greater detail. + + +BUFFER SIZES: +- if HPN is disabled the receive buffer size will be set to the OpenSSH default + of 64K. + +- if a HPN system connects to a non-HPN system the receive buffer will + be set to the HPNBufferSize value. The default is 2MB but user adjustable. + +- If a HPN to HPN connection is established a number of different things might + happen based on the user options and conditions. + + Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set + Result: HPN Buffer Size = up to 64MB + This is the default state. The HPN buffer size will grow to a maximum of + 64MB as the TCP receive buffer grows. The maximum HPN Buffer size of 64MB + is geared towards 10GigE transcontinental connections. + + Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set + Result: HPN Buffer Size = TCP receive buffer value. + Users on non-autotuning systesm should disable TCPRcvBufPoll in the + ssh_cofig and sshd_config + + Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set + Result: HPN Buffer Size = minmum of TCP receive buffer and HPNBufferSize. + This would be the system defined TCP receive buffer (RWIN). + + Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf SET + Result: HPN Buffer Size = minmum of TCPRcvBuf and HPNBufferSize. + Generally there is no need to set both. + + Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set + Result: HPN Buffer Size = grows to HPNBufferSize + The buffer will grow up to the maximum size specified here. + + Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf SET + Result: HPN Buffer Size = minmum of TCPRcvBuf and HPNBufferSize. + Generally there is no need to set both of these, especially on autotuning + systems. However, if the users wishes to override the autotuning this would + be one way to do it. + + Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf SET + Result: HPN Buffer Size = TCPRcvBuf. + This will override autotuning and set the TCP recieve buffer to the user + defined value. + + +HPN SPECIFIC CONFIGURATION OPTIONS: + +- HPNDisabled=[yes/no] client/server + In some situations, such as transfers on a local area network, the impact + of the HPN code produces a net decrease in performance. In these cases it is + helpful to disable the HPN functionality. By default HPNDisabled is set to no. + +- HPNBufferSize=[int]KB client/server + This is the default buffer size the HPN functionality uses when interacting + with non-HPN SSH installations. Conceptually this is similar to the TcpRcvBuf + option as applied to the internal SSH flow control. This value can range from + 1KB to 64MB (1-65536). Use of oversized or undersized buffers can cause + performance problems depending on the roud trip time of the network path. + The default size of this buffer is 2MB. + +- TcpRcvBufPoll=[yes/no] client/server + Enable or disable the polling of the TCP receive buffer through the life + of the connection. You would want to make sure that this option is enabled + for systems making use of autotuning kernels (linux 2.4.24+, 2.6, MS Vista, + FreeBSD 7.x and later). Default is yes. + +- TcpRcvBuf=[int]KB client + Set the TCP socket receive buffer to n Kilobytes. It can be set up to the + maximum socket size allowed by the system. This is useful in situations where + the TCP receive window is set low but the maximum buffer size is set higher + (as is typical). This works on a per TCP connection basis. You can also use + this to artifically limit the transfer rate of the connection. In these cases + the throughput will be no more than n/RTT. The minimum buffer size is 1KB. + Default is the current system wide TCP receive buffer size. + +- NoneEnabled=[yes/no] client/server + Enable or disable the use of the None cipher. Care must always be used when + enabling this as it will allow users to send data in the clear. However, it + is important to note that authentication information remains encrypted even + if this option is enabled. Set to no by default. + +- NoneSwitch=[yes/no] client + Switch the encryption cipher being used to the None cipher after + authentication takes place. NoneEnabled must be enabled on both the client + and server side of the connection. When the connection switches to the NONE + cipher a warning is sent to STDERR. The connection attempt will fail with an + error if a client requests a NoneSwitch from the server that does not + explicitly have NoneEnabled set to yes. + Note: The NONE cipher cannot be used in interactive (shell) sessions and it + will fail silently. Set to no by default. + + +CREDITS: + + This patch was conceived, designed, and led by Chris Rapier (rapier@psc.edu) + The majority of the actual coding for versions up to HPN12v1 was performed + by Michael Stevens (mstevens@andrew.cmu.edu). + The MT-AES-CTR cipher was implemented by Ben Bennet (ben@psc.edu). + This work was financed, in part, by Cisco System, Inc., the National Library + of Medicine, and the National Science Foundation. diff --git a/crypto/openssh/buffer.c b/crypto/openssh/buffer.c index ae9700344d2a..a3202c601d57 100644 --- a/crypto/openssh/buffer.c +++ b/crypto/openssh/buffer.c @@ -1,4 +1,5 @@ /* $OpenBSD: buffer.c,v 1.32 2010/02/09 03:56:28 djm Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -25,7 +26,7 @@ #include "log.h" #define BUFFER_MAX_CHUNK 0x100000 -#define BUFFER_MAX_LEN 0xa00000 +#define BUFFER_MAX_LEN 0x4000000 /* 64MB */ #define BUFFER_ALLOCSZ 0x008000 /* Initializes the buffer structure. */ @@ -165,6 +166,13 @@ buffer_len(const Buffer *buffer) return buffer->end - buffer->offset; } +/* Returns the maximum number of bytes of data that may be in the buffer. */ +u_int +buffer_get_max_len(void) +{ + return (BUFFER_MAX_LEN); +} + /* Gets data from the beginning of the buffer. */ int diff --git a/crypto/openssh/buffer.h b/crypto/openssh/buffer.h index e2a9dd1002a0..c35f53fe428a 100644 --- a/crypto/openssh/buffer.h +++ b/crypto/openssh/buffer.h @@ -1,4 +1,5 @@ /* $OpenBSD: buffer.h,v 1.21 2010/08/31 11:54:45 djm Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen @@ -46,6 +47,8 @@ int buffer_get_ret(Buffer *, void *, u_int); int buffer_consume_ret(Buffer *, u_int); int buffer_consume_end_ret(Buffer *, u_int); +u_int buffer_get_max_len(void); + #include void buffer_put_bignum(Buffer *, const BIGNUM *); diff --git a/crypto/openssh/channels.c b/crypto/openssh/channels.c index 6abe2d012730..bf7072a1c0e6 100644 --- a/crypto/openssh/channels.c +++ b/crypto/openssh/channels.c @@ -1,4 +1,5 @@ /* $OpenBSD: channels.c,v 1.310 2010/11/24 01:24:14 djm Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -170,6 +171,11 @@ static void port_open_helper(Channel *c, char *rtype); static int connect_next(struct channel_connect *); static void channel_connect_ctx_free(struct channel_connect *); +/* -- HPN */ + +static int hpn_disabled = 0; +static u_int buffer_size = CHAN_HPN_MIN_WINDOW_DEFAULT; + /* -- channel core */ Channel * @@ -309,6 +315,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, c->self = found; c->type = type; c->ctype = ctype; + c->dynamic_window = 0; c->local_window = window; c->local_window_max = window; c->local_consumed = 0; @@ -808,11 +815,46 @@ channel_pre_open_13(Channel *c, fd_set *readset, fd_set *writeset) FD_SET(c->sock, writeset); } +static u_int +channel_tcpwinsz(void) +{ + u_int32_t tcpwinsz; + socklen_t optsz; + int ret, sd; + u_int maxlen; + + /* If we are not on a socket return 128KB. */ + if (!packet_connection_is_on_socket()) + return (128 * 1024); + + tcpwinsz = 0; + optsz = sizeof(tcpwinsz); + sd = packet_get_connection_in(); + ret = getsockopt(sd, SOL_SOCKET, SO_RCVBUF, &tcpwinsz, &optsz); + + /* Return no more than the maximum buffer size. */ + maxlen = buffer_get_max_len(); + if ((ret == 0) && tcpwinsz > maxlen) + tcpwinsz = maxlen; + /* In case getsockopt() failed return a minimum. */ + if (tcpwinsz == 0) + tcpwinsz = CHAN_TCP_WINDOW_DEFAULT; + debug2("tcpwinsz: %d for connection: %d", tcpwinsz, sd); + return (tcpwinsz); +} + static void channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset) { - u_int limit = compat20 ? c->remote_window : packet_get_maxsize(); + u_int limit; + /* Check buffer limits. */ + if (!c->tcpwinsz || c->dynamic_window > 0) + c->tcpwinsz = channel_tcpwinsz(); + + limit = MIN(compat20 ? c->remote_window : packet_get_maxsize(), + 2 * c->tcpwinsz); + if (c->istate == CHAN_INPUT_OPEN && limit > 0 && buffer_len(&c->input) < limit && @@ -1789,14 +1831,25 @@ channel_check_window(Channel *c) c->local_maxpacket*3) || c->local_window < c->local_window_max/2) && c->local_consumed > 0) { + u_int addition = 0; + + /* Adjust max window size if we are in a dynamic environment. */ + if (c->dynamic_window && c->tcpwinsz > c->local_window_max) { + /* + * Grow the window somewhat aggressively to maintain + * pressure. + */ + addition = 1.5 * (c->tcpwinsz - c->local_window_max); + c->local_window_max += addition; + } packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); packet_put_int(c->remote_id); - packet_put_int(c->local_consumed); + packet_put_int(c->local_consumed + addition); packet_send(); debug2("channel %d: window %d sent adjust %d", c->self, c->local_window, c->local_consumed); - c->local_window += c->local_consumed; + c->local_window += c->local_consumed + addition; c->local_consumed = 0; } return 1; @@ -2634,6 +2687,15 @@ channel_set_af(int af) IPv4or6 = af; } +void +channel_set_hpn(int disabled, u_int buf_size) +{ + hpn_disabled = disabled; + buffer_size = buf_size; + debug("HPN Disabled: %d, HPN Buffer Size: %d", + hpn_disabled, buffer_size); +} + static int channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port, int *allocated_listen_port, @@ -2786,10 +2848,18 @@ channel_setup_fwd_listener(int type, const char *listen_addr, *allocated_listen_port); } - /* Allocate a channel number for the socket. */ - c = channel_new("port listener", type, sock, sock, -1, - CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, - 0, "port listener", 1); + /* + * Allocate a channel number for the socket. Explicitly test + * for hpn disabled option. If true use smaller window size. + */ + if (hpn_disabled) + c = channel_new("port listener", type, sock, sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, + 0, "port listener", 1); + else + c = channel_new("port listener", type, sock, sock, -1, + buffer_size, CHAN_TCP_PACKET_DEFAULT, + 0, "port listener", 1); c->path = xstrdup(host); c->host_port = port_to_connect; c->listening_port = listen_port; @@ -3334,10 +3404,16 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost, *chanids = xcalloc(num_socks + 1, sizeof(**chanids)); for (n = 0; n < num_socks; n++) { sock = socks[n]; - nc = channel_new("x11 listener", - SSH_CHANNEL_X11_LISTENER, sock, sock, -1, - CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, - 0, "X11 inet listener", 1); + if (hpn_disabled) + nc = channel_new("x11 listener", + SSH_CHANNEL_X11_LISTENER, sock, sock, -1, + CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, + 0, "X11 inet listener", 1); + else + nc = channel_new("x11 listener", + SSH_CHANNEL_X11_LISTENER, sock, sock, -1, + buffer_size, CHAN_X11_PACKET_DEFAULT, + 0, "X11 inet listener", 1); nc->single_connection = single_connection; (*chanids)[n] = nc->self; } diff --git a/crypto/openssh/channels.h b/crypto/openssh/channels.h index 0680ed00e465..a967a7e1aa9e 100644 --- a/crypto/openssh/channels.h +++ b/crypto/openssh/channels.h @@ -1,4 +1,5 @@ /* $OpenBSD: channels.h,v 1.104 2010/05/14 23:29:23 djm Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen @@ -125,6 +126,8 @@ struct Channel { u_int local_window_max; u_int local_consumed; u_int local_maxpacket; + u_int tcpwinsz; + int dynamic_window; int extended_usage; int single_connection; @@ -162,11 +165,15 @@ struct Channel { /* default window/packet sizes for tcp/x11-fwd-channel */ #define CHAN_SES_PACKET_DEFAULT (32*1024) #define CHAN_SES_WINDOW_DEFAULT (64*CHAN_SES_PACKET_DEFAULT) + #define CHAN_TCP_PACKET_DEFAULT (32*1024) #define CHAN_TCP_WINDOW_DEFAULT (64*CHAN_TCP_PACKET_DEFAULT) + #define CHAN_X11_PACKET_DEFAULT (16*1024) #define CHAN_X11_WINDOW_DEFAULT (4*CHAN_X11_PACKET_DEFAULT) +#define CHAN_HPN_MIN_WINDOW_DEFAULT (2*1024*1024) + /* possible input states */ #define CHAN_INPUT_OPEN 0 #define CHAN_INPUT_WAIT_DRAIN 1 @@ -294,4 +301,7 @@ void chan_rcvd_ieof(Channel *); void chan_write_failed(Channel *); void chan_obuf_empty(Channel *); +/* hpn handler */ +void channel_set_hpn(int, u_int); + #endif diff --git a/crypto/openssh/cipher.c b/crypto/openssh/cipher.c index bb5c0ac3a2c2..28afa4597f02 100644 --- a/crypto/openssh/cipher.c +++ b/crypto/openssh/cipher.c @@ -1,4 +1,5 @@ /* $OpenBSD: cipher.c,v 1.82 2009/01/26 09:58:15 markus Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -163,7 +164,12 @@ ciphers_valid(const char *names) for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; (p = strsep(&cp, CIPHER_SEP))) { c = cipher_by_name(p); - if (c == NULL || c->number != SSH_CIPHER_SSH2) { +#ifdef NONE_CIPHER_ENABLED + if (c == NULL || (c->number != SSH_CIPHER_SSH2 && + c->number != SSH_CIPHER_NONE)) { +#else + if (c == NULL || (c->number != SSH_CIPHER_SSH2)) { +#endif debug("bad cipher %s [%s]", p, names); xfree(cipher_list); return 0; @@ -337,6 +343,9 @@ cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len) int evplen; switch (c->number) { +#ifdef NONE_CIPHER_ENABLED + case SSH_CIPHER_NONE: +#endif case SSH_CIPHER_SSH2: case SSH_CIPHER_DES: case SSH_CIPHER_BLOWFISH: @@ -371,6 +380,9 @@ cipher_set_keyiv(CipherContext *cc, u_char *iv) int evplen = 0; switch (c->number) { +#ifdef NONE_CIPHER_ENABLED + case SSH_CIPHER_NONE: +#endif case SSH_CIPHER_SSH2: case SSH_CIPHER_DES: case SSH_CIPHER_BLOWFISH: diff --git a/crypto/openssh/clientloop.c b/crypto/openssh/clientloop.c index f6c1444a385b..05487f266d6a 100644 --- a/crypto/openssh/clientloop.c +++ b/crypto/openssh/clientloop.c @@ -1,4 +1,5 @@ /* $OpenBSD: clientloop.c,v 1.231 2011/01/16 12:05:59 djm Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1768,9 +1769,14 @@ client_request_x11(const char *request_type, int rchan) sock = x11_connect_display(); if (sock < 0) return NULL; - c = channel_new("x11", - SSH_CHANNEL_X11_OPEN, sock, sock, -1, - CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1); + if (options.hpn_disabled) + c = channel_new("x11", SSH_CHANNEL_X11_OPEN, sock, sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, + 0, "x11", 1); + else + c = channel_new("x11", SSH_CHANNEL_X11_OPEN, sock, sock, -1, + options.hpn_buffer_size, CHAN_X11_PACKET_DEFAULT, + 0, "x11", 1); c->force_drain = 1; return c; } @@ -1790,10 +1796,16 @@ client_request_agent(const char *request_type, int rchan) sock = ssh_get_authentication_socket(); if (sock < 0) return NULL; - c = channel_new("authentication agent connection", - SSH_CHANNEL_OPEN, sock, sock, -1, - CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, - "authentication agent connection", 1); + if (options.hpn_disabled) + c = channel_new("authentication agent connection", + SSH_CHANNEL_OPEN, sock, sock, -1, + CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0, + "authentication agent connection", 1); + else + c = channel_new("authentication agent connection", + SSH_CHANNEL_OPEN, sock, sock, -1, + options.hpn_buffer_size, options.hpn_buffer_size, 0, + "authentication agent connection", 1); c->force_drain = 1; return c; } @@ -1820,8 +1832,14 @@ client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun) return -1; } - c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1, - CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); + if (options.hpn_disabled) + c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, + 0, "tun", 1); + else + c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1, + options.hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, + 0, "tun", 1); c->datagram = 1; #if defined(SSH_TUN_FILTER) diff --git a/crypto/openssh/compat.c b/crypto/openssh/compat.c index df3541df70ef..d685f6dc9aef 100644 --- a/crypto/openssh/compat.c +++ b/crypto/openssh/compat.c @@ -1,4 +1,5 @@ /* $OpenBSD: compat.c,v 1.78 2008/09/11 14:22:37 markus Exp $ */ +/* $FreeBSD$ */ /* * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. * @@ -170,6 +171,16 @@ compat_datafellows(const char *version) strlen(check[i].pat), 0) == 1) { debug("match: %s pat %s", version, check[i].pat); datafellows = check[i].bugs; + /* + * Check to see if the remote side is OpenSSH and not + * HPN. It is utterly strange to check it from the + * version string and expose the option that way. + */ + if (strstr(version,"OpenSSH") != NULL && + strstr(version,"hpn") == NULL) { + datafellows |= SSH_BUG_LARGEWINDOW; + debug("Remote is not HPN-aware"); + } return; } } diff --git a/crypto/openssh/compat.h b/crypto/openssh/compat.h index 16cf282a7aec..b8405267fdeb 100644 --- a/crypto/openssh/compat.h +++ b/crypto/openssh/compat.h @@ -1,4 +1,5 @@ /* $OpenBSD: compat.h,v 1.42 2008/09/11 14:22:37 markus Exp $ */ +/* $FReeBSD$ */ /* * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. @@ -58,6 +59,7 @@ #define SSH_OLD_FORWARD_ADDR 0x01000000 #define SSH_BUG_RFWD_ADDR 0x02000000 #define SSH_NEW_OPENSSH 0x04000000 +#define SSH_BUG_LARGEWINDOW 0x08000000 void enable_compat13(void); void enable_compat20(void); diff --git a/crypto/openssh/kex.c b/crypto/openssh/kex.c index c65e28f94dec..ca3c4206a106 100644 --- a/crypto/openssh/kex.c +++ b/crypto/openssh/kex.c @@ -1,4 +1,5 @@ /* $OpenBSD: kex.c,v 1.86 2010/09/22 05:01:29 djm Exp $ */ +/* $FreeBSD$ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * @@ -90,8 +91,13 @@ kex_names_valid(const char *names) return 1; } -/* put algorithm proposal into buffer */ +/* Put algorithm proposal into buffer. */ +#ifndef NONE_CIPHER_ENABLED static void +#else +/* Also used in sshconnect2.c. */ +void +#endif kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) { u_int i; @@ -407,6 +413,9 @@ kex_choose_conf(Kex *kex) int nenc, nmac, ncomp; u_int mode, ctos, need; int first_kex_follows, type; +#ifdef NONE_CIPHER_ENABLED + int auth_flag; +#endif my = kex_buf2prop(&kex->my, NULL); peer = kex_buf2prop(&kex->peer, &first_kex_follows); @@ -430,6 +439,10 @@ kex_choose_conf(Kex *kex) } /* Algorithm Negotiation */ +#ifdef NONE_CIPHER_ENABLED + auth_flag = packet_get_authentication_state(); + debug ("AUTH STATE is %d", auth_flag); +#endif for (mode = 0; mode < MODE_MAX; mode++) { newkeys = xcalloc(1, sizeof(*newkeys)); kex->newkeys[mode] = newkeys; @@ -441,6 +454,17 @@ kex_choose_conf(Kex *kex) choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); +#ifdef NONE_CIPHER_ENABLED + debug("REQUESTED ENC.NAME is '%s'", newkeys->enc.name); + if (strcmp(newkeys->enc.name, "none") == 0) { + debug("Requesting NONE. Authflag is %d", auth_flag); + if (auth_flag == 1) + debug("None requested post authentication."); + else + fatal("Pre-authentication none cipher requests " + "are not allowed."); + } +#endif debug("kex: %s %s %s %s", ctos ? "client->server" : "server->client", newkeys->enc.name, diff --git a/crypto/openssh/kex.h b/crypto/openssh/kex.h index 7373d3c789f4..fc5bdf6e03ae 100644 --- a/crypto/openssh/kex.h +++ b/crypto/openssh/kex.h @@ -1,4 +1,5 @@ /* $OpenBSD: kex.h,v 1.52 2010/09/22 05:01:29 djm Exp $ */ +/* $FreeBSD$ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -140,6 +141,10 @@ struct Kex { int kex_names_valid(const char *); +#ifdef NONE_CIPHER_ENABLED +void kex_prop2buf(Buffer *, char *[PROPOSAL_MAX]); +#endif + Kex *kex_setup(char *[PROPOSAL_MAX]); void kex_finish(Kex *); diff --git a/crypto/openssh/misc.c b/crypto/openssh/misc.c index 919b04e6b7a9..1fc3ae74cb85 100644 --- a/crypto/openssh/misc.c +++ b/crypto/openssh/misc.c @@ -1,4 +1,5 @@ /* $OpenBSD: misc.c,v 1.84 2010/11/21 01:01:13 djm Exp $ */ +/* $FreeBSD$ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005,2006 Damien Miller. All rights reserved. @@ -996,3 +997,34 @@ sock_set_v6only(int s) error("setsockopt IPV6_V6ONLY: %s", strerror(errno)); #endif } + +void +sock_get_rcvbuf(int *size, int rcvbuf) +{ + int sock, socksize; + socklen_t socksizelen = sizeof(socksize); + + /* + * Create a socket but do not connect it. We use it + * only to get the rcv socket size. + */ + sock = socket(AF_INET6, SOCK_STREAM, 0); + if (sock < 0) + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) + return; + + /* + * If the tcp_rcv_buf option is set and passed in, attempt to set the + * buffer size to its value. + */ + if (rcvbuf) + setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&rcvbuf, + sizeof(rcvbuf)); + + if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, + &socksize, &socksizelen) == 0) + if (size != NULL) + *size = socksize; + close(sock); +} diff --git a/crypto/openssh/misc.h b/crypto/openssh/misc.h index 65cf4a6163f3..19149ed3fc20 100644 --- a/crypto/openssh/misc.h +++ b/crypto/openssh/misc.h @@ -1,4 +1,5 @@ /* $OpenBSD: misc.h,v 1.47 2010/11/21 01:01:13 djm Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen @@ -36,6 +37,7 @@ void sanitise_stdfd(void); void ms_subtract_diff(struct timeval *, int *); void ms_to_timeval(struct timeval *, int); void sock_set_v6only(int); +void sock_get_rcvbuf(int *, int); struct passwd *pwcopy(struct passwd *); const char *ssh_gai_strerror(int); diff --git a/crypto/openssh/myproposal.h b/crypto/openssh/myproposal.h index 2c43607a7bd6..30948c2f9e24 100644 --- a/crypto/openssh/myproposal.h +++ b/crypto/openssh/myproposal.h @@ -1,4 +1,5 @@ /* $OpenBSD: myproposal.h,v 1.27 2010/09/01 22:42:13 djm Exp $ */ +/* $FreeBSD$ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -75,6 +76,10 @@ "arcfour256,arcfour128," \ "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \ "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se" +#ifdef NONE_CIPHER_ENABLED +#define KEX_ENCRYPT_INCLUDE_NONE KEX_DEFAULT_ENCRYPT \ + ",none" +#endif #define KEX_DEFAULT_MAC \ "hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160," \ "hmac-ripemd160@openssh.com," \ diff --git a/crypto/openssh/packet.c b/crypto/openssh/packet.c index b4e01f716b47..6f2bdc390af9 100644 --- a/crypto/openssh/packet.c +++ b/crypto/openssh/packet.c @@ -1,4 +1,5 @@ /* $OpenBSD: packet.c,v 1.172 2010/11/13 23:27:50 djm Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -195,6 +196,9 @@ struct session_state { }; static struct session_state *active_state, *backup_state; +#ifdef NONE_CIPHER_ENABLED +static int rekey_requested = 0; +#endif static struct session_state * alloc_session_state(void) @@ -1861,12 +1865,26 @@ packet_send_ignore(int nbytes) } } +#ifdef NONE_CIPHER_ENABLED +void +packet_request_rekeying(void) +{ + rekey_requested = 1; +} +#endif + #define MAX_PACKETS (1U<<31) int packet_need_rekeying(void) { if (datafellows & SSH_BUG_NOREKEY) return 0; +#ifdef NONE_CIPHER_ENABLED + if (rekey_requested == 1) { + rekey_requested = 0; + return 1; + } +#endif return (active_state->p_send.packets > MAX_PACKETS) || (active_state->p_read.packets > MAX_PACKETS) || @@ -1958,3 +1976,11 @@ packet_restore_state(void) add_recv_bytes(len); } } + +#ifdef NONE_CIPHER_ENABLED +int +packet_get_authentication_state(void) +{ + return (active_state->after_authentication); +} +#endif diff --git a/crypto/openssh/packet.h b/crypto/openssh/packet.h index d516aae8d491..16e33cdcd53f 100644 --- a/crypto/openssh/packet.h +++ b/crypto/openssh/packet.h @@ -1,4 +1,5 @@ /* $OpenBSD: packet.h,v 1.55 2010/11/13 23:27:50 djm Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen @@ -38,6 +39,9 @@ void packet_set_interactive(int, int, int); int packet_is_interactive(void); void packet_set_server(void); void packet_set_authenticated(void); +#ifdef NONE_CIPHER_ENABLED +int packet_get_authentication_state(void); +#endif void packet_start(u_char); void packet_put_char(int ch); @@ -117,6 +121,9 @@ do { \ } while (0) int packet_need_rekeying(void); +#ifdef NONE_CIPHER_ENABLED +void packet_request_rekeying(void); +#endif void packet_set_rekey_limit(u_int32_t); void packet_backup_state(void); diff --git a/crypto/openssh/readconf.c b/crypto/openssh/readconf.c index 43779afe7915..17a93a641241 100644 --- a/crypto/openssh/readconf.c +++ b/crypto/openssh/readconf.c @@ -1,4 +1,5 @@ /* $OpenBSD: readconf.c,v 1.190 2010/11/13 23:27:50 djm Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -138,6 +139,10 @@ typedef enum { oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, oKexAlgorithms, oIPQoS, + oHPNDisabled, oHPNBufferSize, oTcpRcvBufPoll, oTcpRcvBuf, +#ifdef NONE_CIPHER_ENABLED + oNoneEnabled, oNoneSwitch, +#endif oVersionAddendum, oDeprecated, oUnsupported } OpCodes; @@ -249,6 +254,14 @@ static struct { #endif { "kexalgorithms", oKexAlgorithms }, { "ipqos", oIPQoS }, + { "hpndisabled", oHPNDisabled }, + { "hpnbuffersize", oHPNBufferSize }, + { "tcprcvbufpoll", oTcpRcvBufPoll }, + { "tcprcvbuf", oTcpRcvBuf }, +#ifdef NONE_CIPHER_ENABLED + { "noneenabled", oNoneEnabled }, + { "noneswitch", oNoneSwitch }, +#endif { "versionaddendum", oVersionAddendum }, { NULL, oBadOption } @@ -1021,6 +1034,47 @@ process_config_line(Options *options, const char *host, } while (arg != NULL && *arg != '\0'); break; + case oHPNDisabled: + intptr = &options->hpn_disabled; + goto parse_flag; + + case oHPNBufferSize: + intptr = &options->hpn_buffer_size; + goto parse_int; + + case oTcpRcvBufPoll: + intptr = &options->tcp_rcv_buf_poll; + goto parse_flag; + + case oTcpRcvBuf: + intptr = &options->tcp_rcv_buf; + goto parse_int; + +#ifdef NONE_CIPHER_ENABLED + case oNoneEnabled: + intptr = &options->none_enabled; + goto parse_flag; + + /* + * We check to see if the command comes from the command line or not. + * If it does then enable it otherwise fail. NONE must never be a + * default configuration. + */ + case oNoneSwitch: + if (strcmp(filename,"command-line") == 0) { + intptr = &options->none_switch; + goto parse_flag; + } else { + debug("NoneSwitch directive found in %.200s.", + filename); + error("NoneSwitch is found in %.200s.\n" + "You may only use this configuration option " + "from the command line", filename); + error("Continuing..."); + return 0; + } +#endif + case oDeprecated: debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); @@ -1181,6 +1235,14 @@ initialize_options(Options * options) options->zero_knowledge_password_authentication = -1; options->ip_qos_interactive = -1; options->ip_qos_bulk = -1; + options->hpn_disabled = -1; + options->hpn_buffer_size = -1; + options->tcp_rcv_buf_poll = -1; + options->tcp_rcv_buf = -1; +#ifdef NONE_CIPHER_ENABLED + options->none_enabled = -1; + options->none_switch = -1; +#endif } /* @@ -1345,6 +1407,36 @@ 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->hpn_disabled == -1) + options->hpn_disabled = 0; + if (options->hpn_buffer_size > -1) + { + u_int maxlen; + + /* If a user tries to set the size to 0 set it to 1KB. */ + if (options->hpn_buffer_size == 0) + options->hpn_buffer_size = 1024; + /* Limit the buffer to BUFFER_MAX_LEN. */ + maxlen = buffer_get_max_len(); + if (options->hpn_buffer_size > (maxlen / 1024)) { + debug("User requested buffer larger than %ub: %ub. " + "Request reverted to %ub", maxlen, + options->hpn_buffer_size * 1024, maxlen); + options->hpn_buffer_size = maxlen; + } + debug("hpn_buffer_size set to %d", options->hpn_buffer_size); + } + if (options->tcp_rcv_buf == 0) + options->tcp_rcv_buf = 1; + if (options->tcp_rcv_buf > -1) + options->tcp_rcv_buf *= 1024; + if (options->tcp_rcv_buf_poll == -1) + options->tcp_rcv_buf_poll = 1; +#ifdef NONE_CIPHER_ENABLED + /* options->none_enabled must not be set by default */ + if (options->none_switch == -1) + options->none_switch = 0; +#endif } /* diff --git a/crypto/openssh/readconf.h b/crypto/openssh/readconf.h index ee160dfe7b1c..195f6e74d62a 100644 --- a/crypto/openssh/readconf.h +++ b/crypto/openssh/readconf.h @@ -1,4 +1,5 @@ /* $OpenBSD: readconf.h,v 1.88 2010/11/13 23:27:50 djm Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen @@ -132,6 +133,17 @@ typedef struct { int use_roaming; + int hpn_disabled; /* Switch to disable HPN buffer management. */ + int hpn_buffer_size; /* User definable size for HPN buffer + * window. */ + int tcp_rcv_buf_poll; /* Option to poll recv buf every window + * transfer. */ + int tcp_rcv_buf; /* User switch to set tcp recv buffer. */ + +#ifdef NONE_CIPHER_ENABLED + int none_enabled; /* Allow none to be used */ + int none_switch; /* Use none cipher */ +#endif } Options; #define SSHCTL_MASTER_NO 0 diff --git a/crypto/openssh/servconf.c b/crypto/openssh/servconf.c index c742e13098cc..96761e7251de 100644 --- a/crypto/openssh/servconf.c +++ b/crypto/openssh/servconf.c @@ -1,4 +1,5 @@ /* $OpenBSD: servconf.c,v 1.213 2010/11/13 23:27:50 djm Exp $ */ +/* $FreeBSD$ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -141,6 +142,12 @@ initialize_server_options(ServerOptions *options) options->authorized_principals_file = NULL; options->ip_qos_interactive = -1; options->ip_qos_bulk = -1; + options->hpn_disabled = -1; + options->hpn_buffer_size = -1; + options->tcp_rcv_buf_poll = -1; +#ifdef NONE_CIPHER_ENABLED + options->none_enabled = -1; +#endif } void @@ -283,6 +290,37 @@ fill_default_server_options(ServerOptions *options) options->ip_qos_interactive = IPTOS_LOWDELAY; if (options->ip_qos_bulk == -1) options->ip_qos_bulk = IPTOS_THROUGHPUT; + if (options->hpn_disabled == -1) + options->hpn_disabled = 0; + if (options->hpn_buffer_size == -1) { + /* + * HPN buffer size option not explicitly set. Try to figure + * out what value to use or resort to default. + */ + options->hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT; + if (!options->hpn_disabled) { + sock_get_rcvbuf(&options->hpn_buffer_size, 0); + debug ("HPN Buffer Size: %d", options->hpn_buffer_size); + } + } else { + /* + * In the case that the user sets both values in a + * contradictory manner hpn_disabled overrrides hpn_buffer_size. + */ + if (options->hpn_disabled <= 0) { + u_int maxlen; + + maxlen = buffer_get_max_len(); + if (options->hpn_buffer_size == 0) + options->hpn_buffer_size = 1; + /* Limit the maximum buffer to BUFFER_MAX_LEN. */ + if (options->hpn_buffer_size > maxlen / 1024) + options->hpn_buffer_size = maxlen; + else + options->hpn_buffer_size *= 1024; + } else + options->hpn_buffer_size = CHAN_TCP_WINDOW_DEFAULT; + } /* Turn privilege separation on by default */ if (use_privsep == -1) @@ -330,6 +368,10 @@ typedef enum { sZeroKnowledgePasswordAuthentication, sHostCertificate, sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, sKexAlgorithms, sIPQoS, + sHPNDisabled, sHPNBufferSize, sTcpRcvBufPoll, +#ifdef NONE_CIPHER_ENABLED + sNoneEnabled, +#endif sVersionAddendum, sDeprecated, sUnsupported } ServerOpCodes; @@ -455,6 +497,12 @@ static struct { { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL }, { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL }, { "ipqos", sIPQoS, SSHCFG_ALL }, + { "hpndisabled", sHPNDisabled, SSHCFG_ALL }, + { "hpnbuffersize", sHPNBufferSize, SSHCFG_ALL }, + { "tcprcvbufpoll", sTcpRcvBufPoll, SSHCFG_ALL }, +#ifdef NONE_CIPHER_ENABLED + { "noneenabled", sNoneEnabled, SSHCFG_ALL }, +#endif { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL }, { NULL, sBadOption, 0 } }; @@ -1409,6 +1457,24 @@ process_server_config_line(ServerOptions *options, char *line, } while (arg != NULL && *arg != '\0'); break; + case sHPNDisabled: + intptr = &options->hpn_disabled; + goto parse_flag; + + case sHPNBufferSize: + intptr = &options->hpn_buffer_size; + goto parse_int; + + case sTcpRcvBufPoll: + intptr = &options->tcp_rcv_buf_poll; + goto parse_flag; + +#ifdef NONE_CIPHER_ENABLED + case sNoneEnabled: + intptr = &options->none_enabled; + goto parse_flag; +#endif + case sDeprecated: logit("%s line %d: Deprecated option %s", filename, linenum, arg); diff --git a/crypto/openssh/servconf.h b/crypto/openssh/servconf.h index 5a058a416443..f6aadac3a80e 100644 --- a/crypto/openssh/servconf.h +++ b/crypto/openssh/servconf.h @@ -1,4 +1,5 @@ /* $OpenBSD: servconf.h,v 1.95 2010/11/13 23:27:50 djm Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen @@ -160,6 +161,15 @@ typedef struct { char *revoked_keys_file; char *trusted_user_ca_keys; char *authorized_principals_file; + + int hpn_disabled; /* Disable HPN functionality. */ + int hpn_buffer_size; /* Set HPN buffer size - default 2MB.*/ + int tcp_rcv_buf_poll; /* Poll TCP rcv window in autotuning + * kernels. */ + +#ifdef NONE_CIPHER_ENABLED + int none_enabled; /* Enable NONE cipher switch. */ +#endif } ServerOptions; void initialize_server_options(ServerOptions *); diff --git a/crypto/openssh/serverloop.c b/crypto/openssh/serverloop.c index 8be01c5c37c4..7606937cca3d 100644 --- a/crypto/openssh/serverloop.c +++ b/crypto/openssh/serverloop.c @@ -1,4 +1,5 @@ /* $OpenBSD: serverloop.c,v 1.159 2009/05/28 16:50:16 andreas Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -726,7 +727,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) /* Wait until all output has been sent to the client. */ drain_output(); - debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.", + debug("End of interactive session; stdin %ld, stdout (read %ld, " "sent %ld), stderr %ld bytes.", stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes); /* Free and clear the buffers. */ @@ -998,8 +999,14 @@ server_request_tun(void) sock = tun_open(tun, mode); if (sock < 0) goto done; - c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1, - CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); + if (options.hpn_disabled) + c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, + "tun", 1); + else + c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1, + options.hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, 0, + "tun", 1); c->datagram = 1; #if defined(SSH_TUN_FILTER) if (mode == SSH_TUNMODE_POINTOPOINT) @@ -1035,6 +1042,8 @@ server_request_session(void) c = channel_new("session", SSH_CHANNEL_LARVAL, -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT, 0, "server-session", 1); + if (!options.hpn_disabled && options.tcp_rcv_buf_poll) + c->dynamic_window = 1; if (session_open(the_authctxt, c->self) != 1) { debug("session open failed, free channel %d", c->self); channel_free(c); diff --git a/crypto/openssh/session.c b/crypto/openssh/session.c index 242a86190f2e..b04e629974b1 100644 --- a/crypto/openssh/session.c +++ b/crypto/openssh/session.c @@ -1,4 +1,5 @@ /* $OpenBSD: session.c,v 1.258 2010/11/25 04:10:09 djm Exp $ */ +/* $FreeBSD$ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -232,7 +233,10 @@ auth_input_request_forwarding(struct passwd * pw) goto authsock_err; } - /* Allocate a channel for the authentication agent socket. */ + /* + * Allocate a channel for the authentication agent socket. + * Ignore HPN on that one given no improvement expected. + */ nc = channel_new("auth socket", SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, @@ -2283,10 +2287,14 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr, int ignore_fderr, */ if (s->chanid == -1) fatal("no channel for session %d", s->self); - channel_set_fds(s->chanid, - fdout, fdin, fderr, - ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, - 1, is_tty, CHAN_SES_WINDOW_DEFAULT); + if (options.hpn_disabled) + channel_set_fds(s->chanid, fdout, fdin, fderr, + ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, + 1, is_tty, CHAN_SES_WINDOW_DEFAULT); + else + channel_set_fds(s->chanid, fdout, fdin, fderr, + ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, + 1, is_tty, options.hpn_buffer_size); } /* diff --git a/crypto/openssh/sftp.1 b/crypto/openssh/sftp.1 index 6b506fec8d63..416948291804 100644 --- a/crypto/openssh/sftp.1 +++ b/crypto/openssh/sftp.1 @@ -242,7 +242,8 @@ diagnostic messages from Specify how many requests may be outstanding at any one time. Increasing this may slightly improve file transfer speed but will increase memory usage. -The default is 64 outstanding requests. +The default is 256 outstanding requests providing for 8MB +of outstanding data with a 32KB buffer. .It Fl r Recursively copy entire directories when uploading and downloading. Note that diff --git a/crypto/openssh/sftp.c b/crypto/openssh/sftp.c index ab667f5a55e0..0fb420a8979e 100644 --- a/crypto/openssh/sftp.c +++ b/crypto/openssh/sftp.c @@ -1,4 +1,5 @@ /* $OpenBSD: sftp.c,v 1.132 2010/12/04 00:18:01 djm Exp $ */ +/* $FreeBSD$ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -69,7 +70,7 @@ typedef void EditLine; #include "sftp-client.h" #define DEFAULT_COPY_BUFLEN 32768 /* Size of buffer for up/download */ -#define DEFAULT_NUM_REQUESTS 64 /* # concurrent outstanding requests */ +#define DEFAULT_NUM_REQUESTS 256 /* # concurrent outstanding requests */ /* File to read commands from */ FILE* infile; diff --git a/crypto/openssh/ssh.c b/crypto/openssh/ssh.c index c9b29fb6b8a8..1d21f9336154 100644 --- a/crypto/openssh/ssh.c +++ b/crypto/openssh/ssh.c @@ -1,4 +1,5 @@ /* $OpenBSD: ssh.c,v 1.356 2011/01/06 22:23:53 djm Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -546,6 +547,15 @@ main(int ac, char **av) break; case 'T': no_tty_flag = 1; +#ifdef NONE_CIPHER_ENABLED + /* + * Ensure that the user does not try to backdoor a + * NONE cipher switch on an interactive session by + * explicitly disabling it if the user asks for a + * session without a tty. + */ + options.none_switch = 0; +#endif break; case 'o': dummy = 1; @@ -1368,9 +1378,46 @@ ssh_session2_open(void) if (!isatty(err)) set_nonblock(err); - window = CHAN_SES_WINDOW_DEFAULT; + /* + * We need to check to see what to do about buffer sizes here. + * - In an HPN to non-HPN connection we want to limit the window size to + * something reasonable in case the far side has the large window bug. + * - In an HPN to HPN connection we want to use the max window size but + * allow the user to override it. + * - Lastly if HPN is disabled then use the ssh standard window size. + * + * We cannot just do a getsockopt() here and set the ssh window to that + * as in case of autotuning of socket buffers the window would get stuck + * at the initial buffer size, generally less than 96k. Therefore we + * need to set the maximum ssh window size to the maximum HPN buffer + * size unless the user has set TcpRcvBufPoll to no. In that case we + * can just set the window to the minimum of HPN buffer size and TCP + * receive buffer size. + */ + if (tty_flag) + options.hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT; + else + options.hpn_buffer_size = CHAN_HPN_MIN_WINDOW_DEFAULT; + + if (datafellows & SSH_BUG_LARGEWINDOW) { + debug("HPN to Non-HPN Connection"); + } else if (options.tcp_rcv_buf_poll <= 0) { + sock_get_rcvbuf(&options.hpn_buffer_size, 0); + debug("HPNBufferSize set to TCP RWIN: %d", + options.hpn_buffer_size); + } else if (options.tcp_rcv_buf > 0) { + sock_get_rcvbuf(&options.hpn_buffer_size, + options.tcp_rcv_buf); + debug("HPNBufferSize set to user TCPRcvBuf: %d", + options.hpn_buffer_size); + } + debug("Final hpn_buffer_size = %d", options.hpn_buffer_size); + channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size); + window = options.hpn_buffer_size; + packetmax = CHAN_SES_PACKET_DEFAULT; if (tty_flag) { + window = CHAN_SES_WINDOW_DEFAULT; window >>= 1; packetmax >>= 1; } @@ -1378,7 +1425,10 @@ ssh_session2_open(void) "session", SSH_CHANNEL_OPENING, in, out, err, window, packetmax, CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); - + if (!options.hpn_disabled && options.tcp_rcv_buf_poll > 0) { + c->dynamic_window = 1; + debug("Enabled Dynamic Window Scaling\n"); + } debug3("ssh_session2_open: channel_new: %d", c->self); channel_send_open(c->self); diff --git a/crypto/openssh/sshconnect.c b/crypto/openssh/sshconnect.c index 3e55b5dd09a0..0615b44f1496 100644 --- a/crypto/openssh/sshconnect.c +++ b/crypto/openssh/sshconnect.c @@ -182,6 +182,29 @@ ssh_kill_proxy_command(void) kill(proxy_command_pid, SIGHUP); } +/* + * Set TCP receive buffer if requested. + * Note: tuning needs to happen after the socket is created but before the + * connection happens so winscale is negotiated properly. + */ +static void +ssh_set_socket_recvbuf(int sock) +{ + void *buf = (void *)&options.tcp_rcv_buf; + int socksize, sz = sizeof(options.tcp_rcv_buf); + socklen_t len = sizeof(int); + + debug("setsockopt attempting to set SO_RCVBUF to %d", + options.tcp_rcv_buf); + if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, buf, sz) >= 0) { + getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &socksize, &len); + debug("setsockopt SO_RCVBUF: %.100s %d", strerror(errno), + socksize); + } else + error("Couldn't set socket receive buffer to %d: %.100s", + options.tcp_rcv_buf, strerror(errno)); +} + /* * Creates a (possibly privileged) socket for use as the ssh connection. */ @@ -205,6 +228,8 @@ ssh_create_socket(int privileged, struct addrinfo *ai) strerror(errno)); else debug("Allocated local port %d.", p); + if (options.tcp_rcv_buf > 0) + ssh_set_socket_recvbuf(sock); return sock; } sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); @@ -214,6 +239,9 @@ ssh_create_socket(int privileged, struct addrinfo *ai) } fcntl(sock, F_SETFD, FD_CLOEXEC); + if (options.tcp_rcv_buf > 0) + ssh_set_socket_recvbuf(sock); + /* Bind the socket to an alternative local IP address */ if (options.bind_address == NULL) return sock; @@ -557,7 +585,7 @@ ssh_exchange_identification(int timeout_ms) snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s%s", compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, compat20 ? PROTOCOL_MINOR_2 : minor1, - SSH_VERSION, compat20 ? "\r\n" : "\n"); + SSH_RELEASE, compat20 ? "\r\n" : "\n"); if (roaming_atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf)) fatal("write: %.100s", strerror(errno)); diff --git a/crypto/openssh/sshconnect2.c b/crypto/openssh/sshconnect2.c index 3cb9b101cb88..7352276fd95f 100644 --- a/crypto/openssh/sshconnect2.c +++ b/crypto/openssh/sshconnect2.c @@ -1,4 +1,5 @@ /* $OpenBSD: sshconnect2.c,v 1.186 2010/11/29 23:45:51 djm Exp $ */ +/* $FreeBSD$ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2008 Damien Miller. All rights reserved. @@ -81,6 +82,16 @@ extern char *client_version_string; extern char *server_version_string; extern Options options; +#ifdef NONE_CIPHER_ENABLED +extern Kex *xxx_kex; + +/* + * tty_flag is set in ssh.c so we can use it here. If set then prevent + * the switch to the null cipher. + */ + +extern int tty_flag; +#endif /* * SSH2 key exchange @@ -419,6 +430,29 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host, pubkey_cleanup(&authctxt); dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL); +#ifdef NONE_CIPHER_ENABLED + /* + * If the user explicitly requests to use the none cipher enable it + * post authentication and only if the right conditions are met: both + * of the NONE switches must be true and there must be no tty allocated. + */ + if (options.none_switch == 1 && options.none_enabled == 1) { + if (!tty_flag) { + debug("Requesting none cipher re-keying..."); + myproposal[PROPOSAL_ENC_ALGS_STOC] = "none"; + myproposal[PROPOSAL_ENC_ALGS_CTOS] = "none"; + kex_prop2buf(&xxx_kex->my, myproposal); + packet_request_rekeying(); + fprintf(stderr, "WARNING: enabled NONE cipher\n"); + } else { + /* Requested NONE cipher on an interactive session. */ + debug("Cannot switch to NONE cipher with tty " + "allocated"); + fprintf(stderr, "NONE cipher switch disabled given " + "a TTY is allocated\n"); + } + } +#endif debug("Authentication succeeded (%s).", authctxt.method->name); } diff --git a/crypto/openssh/sshd.c b/crypto/openssh/sshd.c index 18d2d8e88be1..a6c9943e4fa4 100644 --- a/crypto/openssh/sshd.c +++ b/crypto/openssh/sshd.c @@ -1,4 +1,5 @@ /* $OpenBSD: sshd.c,v 1.381 2011/01/11 06:13:10 djm Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -429,7 +430,7 @@ sshd_exchange_identification(int sock_in, int sock_out) minor = PROTOCOL_MINOR_1; } snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s%s", major, minor, - SSH_VERSION, newline); + SSH_RELEASE, newline); server_version_string = xstrdup(buf); /* Send our protocol version identification. */ @@ -1011,6 +1012,8 @@ server_listen(void) int ret, listen_sock, on = 1; struct addrinfo *ai; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; + int socksize; + socklen_t len; for (ai = options.listen_addrs; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) @@ -1051,6 +1054,11 @@ server_listen(void) debug("Bind to port %s on %s.", strport, ntop); + len = sizeof(socksize); + getsockopt(listen_sock, SOL_SOCKET, SO_RCVBUF, &socksize, &len); + debug("Server TCP RWIN socket size: %d", socksize); + debug("HPN Buffer Size: %d", options.hpn_buffer_size); + /* Bind the socket to the desired port. */ if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) { error("Bind to port %s on %s failed: %.200s.", @@ -1960,6 +1968,9 @@ main(int ac, char **av) /* Log the connection. */ verbose("Connection from %.500s port %d", remote_ip, remote_port); + /* Set HPN options for the child. */ + channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size); + /* * We don't want to listen forever unless the other side * successfully authenticates itself. So we set up an alarm which is @@ -2319,6 +2330,12 @@ do_ssh2_kex(void) if (options.ciphers != NULL) { myproposal[PROPOSAL_ENC_ALGS_CTOS] = myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; +#ifdef NONE_CIPHER_ENABLED + } else if (options.none_enabled == 1) { + debug ("WARNING: None cipher enabled"); + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_ENCRYPT_INCLUDE_NONE; +#endif } myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); diff --git a/crypto/openssh/sshd_config b/crypto/openssh/sshd_config index 7858e78c51a6..f5079513bbb6 100644 --- a/crypto/openssh/sshd_config +++ b/crypto/openssh/sshd_config @@ -117,6 +117,18 @@ # override default of no subsystems Subsystem sftp /usr/libexec/sftp-server +# Disable HPN tuning improvements. +#HPNDisabled no + +# Buffer size for HPN to non-HPN connections. +#HPNBufferSize 2048 + +# TCP receive socket buffer polling for HPN. Disable on non autotuning kernels. +#TcpRcvBufPoll yes + +# Allow the use of the NONE cipher. +#NoneEnabled no + # Example of overriding settings on a per-user basis #Match User anoncvs # X11Forwarding no diff --git a/crypto/openssh/version.c b/crypto/openssh/version.c index 88361ae651a3..3cb4b7a13aba 100644 --- a/crypto/openssh/version.c +++ b/crypto/openssh/version.c @@ -40,7 +40,7 @@ const char * ssh_version_get(void) { if (version == NULL) - version = xstrdup(SSH_VERSION_BASE " " SSH_VERSION_ADDENDUM); + version = xstrdup(SSH_VERSION); return (version); } @@ -50,11 +50,13 @@ ssh_version_set_addendum(const char *add) { size_t size; if (add != NULL) { - size = strlen(SSH_VERSION_BASE) + 1 + strlen(add) + 1; + size = strlen(SSH_VERSION_BASE) + strlen(SSH_VERSION_HPN) + 1 + + strlen(add) + 1; newvers = xmalloc(size); - snprintf(newvers, size, "%s %s", SSH_VERSION_BASE, add); + snprintf(newvers, size, "%s %s", SSH_VERSION_BASE, + SSH_VERSION_HPN, add); } else { - newvers = xstrdup(SSH_VERSION_BASE); + newvers = xstrdup(SSH_VERSION_BASE SSH_VERSION_HPN); } if (version != NULL) xfree(version); diff --git a/crypto/openssh/version.h b/crypto/openssh/version.h index 00dbdf3f692c..a15489290926 100644 --- a/crypto/openssh/version.h +++ b/crypto/openssh/version.h @@ -3,10 +3,11 @@ #ifndef SSH_VERSION -#define SSH_VERSION (ssh_version_get()) -#define SSH_RELEASE (ssh_version_get()) #define SSH_VERSION_BASE "OpenSSH_5.8p2" #define SSH_VERSION_ADDENDUM "FreeBSD-20110503" +#define SSH_VERSION_HPN "_hpn13v11" +#define SSH_VERSION SSH_VERSION_BASE SSH_VERSION_HPN " " SSH_VERSION_ADDENDUM +#define SSH_RELEASE (ssh_version_get()) const char *ssh_version_get(void); void ssh_version_set_addendum(const char *);