]>
Commit | Line | Data |
---|---|---|
8efc0c15 | 1 | /* |
2 | ||
3 | packet.c | |
4 | ||
5 | Author: Tatu Ylonen <ylo@cs.hut.fi> | |
6 | ||
7 | Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | |
8 | All rights reserved | |
9 | ||
10 | Created: Sat Mar 18 02:40:40 1995 ylo | |
11 | ||
12 | This file contains code implementing the packet protocol and communication | |
13 | with the other side. This same code is used both on client and server side. | |
14 | ||
15 | */ | |
16 | ||
17 | #include "includes.h" | |
18 | RCSID("$Id$"); | |
19 | ||
20 | #include "xmalloc.h" | |
21 | #include "buffer.h" | |
22 | #include "packet.h" | |
23 | #include "bufaux.h" | |
24 | #include "ssh.h" | |
25 | #include "crc32.h" | |
26 | #include "cipher.h" | |
27 | #include "getput.h" | |
28 | ||
29 | #include "compress.h" | |
30 | #include "deattack.h" | |
31 | ||
32 | /* This variable contains the file descriptors used for communicating with | |
33 | the other side. connection_in is used for reading; connection_out | |
34 | for writing. These can be the same descriptor, in which case it is | |
35 | assumed to be a socket. */ | |
36 | static int connection_in = -1; | |
37 | static int connection_out = -1; | |
38 | ||
39 | /* Cipher type. This value is only used to determine whether to pad the | |
40 | packets with zeroes or random data. */ | |
41 | static int cipher_type = SSH_CIPHER_NONE; | |
42 | ||
43 | /* Protocol flags for the remote side. */ | |
44 | static unsigned int remote_protocol_flags = 0; | |
45 | ||
46 | /* Encryption context for receiving data. This is only used for decryption. */ | |
47 | static CipherContext receive_context; | |
48 | /* Encryption coontext for sending data. This is only used for encryption. */ | |
49 | static CipherContext send_context; | |
50 | ||
51 | /* Buffer for raw input data from the socket. */ | |
52 | static Buffer input; | |
53 | ||
54 | /* Buffer for raw output data going to the socket. */ | |
55 | static Buffer output; | |
56 | ||
57 | /* Buffer for the partial outgoing packet being constructed. */ | |
58 | static Buffer outgoing_packet; | |
59 | ||
60 | /* Buffer for the incoming packet currently being processed. */ | |
61 | static Buffer incoming_packet; | |
62 | ||
63 | /* Scratch buffer for packet compression/decompression. */ | |
64 | static Buffer compression_buffer; | |
65 | ||
66 | /* Flag indicating whether packet compression/decompression is enabled. */ | |
67 | static int packet_compression = 0; | |
68 | ||
69 | /* Flag indicating whether this module has been initialized. */ | |
70 | static int initialized = 0; | |
71 | ||
72 | /* Set to true if the connection is interactive. */ | |
73 | static int interactive_mode = 0; | |
74 | ||
75 | /* Sets the descriptors used for communication. Disables encryption until | |
76 | packet_set_encryption_key is called. */ | |
77 | ||
78 | void | |
79 | packet_set_connection(int fd_in, int fd_out) | |
80 | { | |
81 | connection_in = fd_in; | |
82 | connection_out = fd_out; | |
83 | cipher_type = SSH_CIPHER_NONE; | |
84 | cipher_set_key(&send_context, SSH_CIPHER_NONE, (unsigned char *)"", 0, 1); | |
85 | cipher_set_key(&receive_context, SSH_CIPHER_NONE, (unsigned char *)"", 0, 0); | |
86 | if (!initialized) | |
87 | { | |
88 | initialized = 1; | |
89 | buffer_init(&input); | |
90 | buffer_init(&output); | |
91 | buffer_init(&outgoing_packet); | |
92 | buffer_init(&incoming_packet); | |
93 | } | |
94 | ||
95 | /* Kludge: arrange the close function to be called from fatal(). */ | |
96 | fatal_add_cleanup((void (*)(void *))packet_close, NULL); | |
97 | } | |
98 | ||
99 | /* Sets the connection into non-blocking mode. */ | |
100 | ||
101 | void | |
102 | packet_set_nonblocking() | |
103 | { | |
104 | /* Set the socket into non-blocking mode. */ | |
105 | if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0) | |
106 | error("fcntl O_NONBLOCK: %.100s", strerror(errno)); | |
107 | ||
108 | if (connection_out != connection_in) | |
109 | { | |
110 | if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0) | |
111 | error("fcntl O_NONBLOCK: %.100s", strerror(errno)); | |
112 | } | |
113 | } | |
114 | ||
115 | /* Returns the socket used for reading. */ | |
116 | ||
117 | int | |
118 | packet_get_connection_in() | |
119 | { | |
120 | return connection_in; | |
121 | } | |
122 | ||
123 | /* Returns the descriptor used for writing. */ | |
124 | ||
125 | int | |
126 | packet_get_connection_out() | |
127 | { | |
128 | return connection_out; | |
129 | } | |
130 | ||
131 | /* Closes the connection and clears and frees internal data structures. */ | |
132 | ||
133 | void | |
134 | packet_close() | |
135 | { | |
136 | if (!initialized) | |
137 | return; | |
138 | initialized = 0; | |
139 | if (connection_in == connection_out) | |
140 | { | |
141 | shutdown(connection_out, SHUT_RDWR); | |
142 | close(connection_out); | |
143 | } | |
144 | else | |
145 | { | |
146 | close(connection_in); | |
147 | close(connection_out); | |
148 | } | |
149 | buffer_free(&input); | |
150 | buffer_free(&output); | |
151 | buffer_free(&outgoing_packet); | |
152 | buffer_free(&incoming_packet); | |
153 | if (packet_compression) | |
154 | { | |
155 | buffer_free(&compression_buffer); | |
156 | buffer_compress_uninit(); | |
157 | } | |
158 | } | |
159 | ||
160 | /* Sets remote side protocol flags. */ | |
161 | ||
162 | void | |
163 | packet_set_protocol_flags(unsigned int protocol_flags) | |
164 | { | |
165 | remote_protocol_flags = protocol_flags; | |
166 | channel_set_options((protocol_flags & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) != 0); | |
167 | } | |
168 | ||
169 | /* Returns the remote protocol flags set earlier by the above function. */ | |
170 | ||
171 | unsigned int | |
172 | packet_get_protocol_flags() | |
173 | { | |
174 | return remote_protocol_flags; | |
175 | } | |
176 | ||
177 | /* Starts packet compression from the next packet on in both directions. | |
178 | Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. */ | |
179 | ||
180 | void | |
181 | packet_start_compression(int level) | |
182 | { | |
183 | if (packet_compression) | |
184 | fatal("Compression already enabled."); | |
185 | packet_compression = 1; | |
186 | buffer_init(&compression_buffer); | |
187 | buffer_compress_init(level); | |
188 | } | |
189 | ||
190 | /* Encrypts the given number of bytes, copying from src to dest. | |
191 | bytes is known to be a multiple of 8. */ | |
192 | ||
193 | void | |
194 | packet_encrypt(CipherContext *cc, void *dest, void *src, | |
195 | unsigned int bytes) | |
196 | { | |
8efc0c15 | 197 | cipher_encrypt(cc, dest, src, bytes); |
198 | } | |
199 | ||
200 | /* Decrypts the given number of bytes, copying from src to dest. | |
201 | bytes is known to be a multiple of 8. */ | |
202 | ||
203 | void | |
204 | packet_decrypt(CipherContext *cc, void *dest, void *src, | |
205 | unsigned int bytes) | |
206 | { | |
207 | int i; | |
208 | ||
5bae4ab8 | 209 | if ((bytes % 8) != 0) |
210 | fatal("packet_decrypt: bad ciphertext length %d", bytes); | |
8efc0c15 | 211 | |
212 | /* | |
213 | Cryptographic attack detector for ssh - Modifications for packet.c | |
214 | (C)1998 CORE-SDI, Buenos Aires Argentina | |
215 | Ariel Futoransky(futo@core-sdi.com) | |
216 | */ | |
217 | switch (cc->type) | |
218 | { | |
219 | case SSH_CIPHER_NONE: | |
220 | i = DEATTACK_OK; | |
221 | break; | |
222 | default: | |
223 | i = detect_attack(src, bytes, NULL); | |
224 | break; | |
225 | } | |
226 | ||
227 | if (i == DEATTACK_DETECTED) | |
228 | packet_disconnect("crc32 compensation attack: network attack detected"); | |
229 | ||
230 | cipher_decrypt(cc, dest, src, bytes); | |
231 | } | |
232 | ||
233 | /* Causes any further packets to be encrypted using the given key. The same | |
234 | key is used for both sending and reception. However, both directions | |
235 | are encrypted independently of each other. */ | |
236 | ||
237 | void | |
238 | packet_set_encryption_key(const unsigned char *key, unsigned int keylen, | |
4d195447 | 239 | int cipher) |
8efc0c15 | 240 | { |
4d195447 | 241 | /* All other ciphers use the same key in both directions for now. */ |
242 | cipher_set_key(&receive_context, cipher, key, keylen, 0); | |
243 | cipher_set_key(&send_context, cipher, key, keylen, 1); | |
8efc0c15 | 244 | } |
245 | ||
246 | /* Starts constructing a packet to send. */ | |
247 | ||
248 | void | |
249 | packet_start(int type) | |
250 | { | |
251 | char buf[9]; | |
252 | ||
253 | buffer_clear(&outgoing_packet); | |
254 | memset(buf, 0, 8); | |
255 | buf[8] = type; | |
256 | buffer_append(&outgoing_packet, buf, 9); | |
257 | } | |
258 | ||
259 | /* Appends a character to the packet data. */ | |
260 | ||
261 | void | |
262 | packet_put_char(int value) | |
263 | { | |
264 | char ch = value; | |
265 | buffer_append(&outgoing_packet, &ch, 1); | |
266 | } | |
267 | ||
268 | /* Appends an integer to the packet data. */ | |
269 | ||
270 | void | |
271 | packet_put_int(unsigned int value) | |
272 | { | |
273 | buffer_put_int(&outgoing_packet, value); | |
274 | } | |
275 | ||
276 | /* Appends a string to packet data. */ | |
277 | ||
278 | void | |
279 | packet_put_string(const char *buf, unsigned int len) | |
280 | { | |
281 | buffer_put_string(&outgoing_packet, buf, len); | |
282 | } | |
283 | ||
284 | /* Appends an arbitrary precision integer to packet data. */ | |
285 | ||
286 | void | |
287 | packet_put_bignum(BIGNUM *value) | |
288 | { | |
289 | buffer_put_bignum(&outgoing_packet, value); | |
290 | } | |
291 | ||
292 | /* Finalizes and sends the packet. If the encryption key has been set, | |
293 | encrypts the packet before sending. */ | |
294 | ||
295 | void | |
296 | packet_send() | |
297 | { | |
298 | char buf[8], *cp; | |
299 | int i, padding, len; | |
300 | unsigned int checksum; | |
301 | u_int32_t rand = 0; | |
302 | ||
303 | /* If using packet compression, compress the payload of the outgoing | |
304 | packet. */ | |
305 | if (packet_compression) | |
306 | { | |
307 | buffer_clear(&compression_buffer); | |
308 | buffer_consume(&outgoing_packet, 8); /* Skip padding. */ | |
309 | buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8); /* padding */ | |
310 | buffer_compress(&outgoing_packet, &compression_buffer); | |
311 | buffer_clear(&outgoing_packet); | |
312 | buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer), | |
313 | buffer_len(&compression_buffer)); | |
314 | } | |
315 | ||
316 | /* Compute packet length without padding (add checksum, remove padding). */ | |
317 | len = buffer_len(&outgoing_packet) + 4 - 8; | |
318 | ||
319 | /* Insert padding. */ | |
320 | padding = 8 - len % 8; | |
321 | if (cipher_type != SSH_CIPHER_NONE) | |
322 | { | |
323 | cp = buffer_ptr(&outgoing_packet); | |
324 | for (i = 0; i < padding; i++) { | |
325 | if (i % 4 == 0) | |
326 | rand = arc4random(); | |
327 | cp[7 - i] = rand & 0xff; | |
328 | rand >>= 8; | |
329 | } | |
330 | } | |
331 | buffer_consume(&outgoing_packet, 8 - padding); | |
332 | ||
333 | /* Add check bytes. */ | |
334 | checksum = crc32((unsigned char *)buffer_ptr(&outgoing_packet), | |
335 | buffer_len(&outgoing_packet)); | |
336 | PUT_32BIT(buf, checksum); | |
337 | buffer_append(&outgoing_packet, buf, 4); | |
338 | ||
339 | #ifdef PACKET_DEBUG | |
340 | fprintf(stderr, "packet_send plain: "); | |
341 | buffer_dump(&outgoing_packet); | |
342 | #endif | |
343 | ||
344 | /* Append to output. */ | |
345 | PUT_32BIT(buf, len); | |
346 | buffer_append(&output, buf, 4); | |
347 | buffer_append_space(&output, &cp, buffer_len(&outgoing_packet)); | |
348 | packet_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet), | |
349 | buffer_len(&outgoing_packet)); | |
350 | ||
351 | #ifdef PACKET_DEBUG | |
352 | fprintf(stderr, "encrypted: "); buffer_dump(&output); | |
353 | #endif | |
354 | ||
355 | buffer_clear(&outgoing_packet); | |
356 | ||
357 | /* Note that the packet is now only buffered in output. It won\'t be | |
358 | actually sent until packet_write_wait or packet_write_poll is called. */ | |
359 | } | |
360 | ||
361 | /* Waits until a packet has been received, and returns its type. Note that | |
362 | no other data is processed until this returns, so this function should | |
363 | not be used during the interactive session. */ | |
364 | ||
365 | int | |
366 | packet_read(int *payload_len_ptr) | |
367 | { | |
368 | int type, len; | |
369 | fd_set set; | |
370 | char buf[8192]; | |
371 | ||
372 | /* Since we are blocking, ensure that all written packets have been sent. */ | |
373 | packet_write_wait(); | |
374 | ||
375 | /* Stay in the loop until we have received a complete packet. */ | |
376 | for (;;) | |
377 | { | |
378 | /* Try to read a packet from the buffer. */ | |
379 | type = packet_read_poll(payload_len_ptr); | |
380 | if (type == SSH_SMSG_SUCCESS | |
381 | || type == SSH_SMSG_FAILURE | |
382 | || type == SSH_CMSG_EOF | |
383 | || type == SSH_CMSG_EXIT_CONFIRMATION) | |
384 | packet_integrity_check(*payload_len_ptr, 0, type); | |
385 | /* If we got a packet, return it. */ | |
386 | if (type != SSH_MSG_NONE) | |
387 | return type; | |
388 | /* Otherwise, wait for some data to arrive, add it to the buffer, | |
389 | and try again. */ | |
390 | FD_ZERO(&set); | |
391 | FD_SET(connection_in, &set); | |
392 | /* Wait for some data to arrive. */ | |
393 | select(connection_in + 1, &set, NULL, NULL, NULL); | |
394 | /* Read data from the socket. */ | |
395 | len = read(connection_in, buf, sizeof(buf)); | |
396 | if (len == 0) | |
397 | fatal("Connection closed by remote host."); | |
398 | if (len < 0) | |
399 | fatal("Read from socket failed: %.100s", strerror(errno)); | |
400 | /* Append it to the buffer. */ | |
401 | packet_process_incoming(buf, len); | |
402 | } | |
403 | /*NOTREACHED*/ | |
404 | } | |
405 | ||
406 | /* Waits until a packet has been received, verifies that its type matches | |
407 | that given, and gives a fatal error and exits if there is a mismatch. */ | |
408 | ||
409 | void | |
410 | packet_read_expect(int *payload_len_ptr, int expected_type) | |
411 | { | |
412 | int type; | |
413 | ||
414 | type = packet_read(payload_len_ptr); | |
415 | if (type != expected_type) | |
416 | packet_disconnect("Protocol error: expected packet type %d, got %d", | |
417 | expected_type, type); | |
418 | } | |
419 | ||
420 | /* Checks if a full packet is available in the data received so far via | |
421 | packet_process_incoming. If so, reads the packet; otherwise returns | |
422 | SSH_MSG_NONE. This does not wait for data from the connection. | |
423 | ||
424 | SSH_MSG_DISCONNECT is handled specially here. Also, | |
425 | SSH_MSG_IGNORE messages are skipped by this function and are never returned | |
426 | to higher levels. | |
427 | ||
428 | The returned payload_len does include space consumed by: | |
429 | Packet length | |
430 | Padding | |
431 | Packet type | |
432 | Check bytes | |
433 | ||
434 | ||
435 | */ | |
436 | ||
437 | int | |
438 | packet_read_poll(int *payload_len_ptr) | |
439 | { | |
440 | unsigned int len, padded_len; | |
441 | unsigned char *ucp; | |
442 | char buf[8], *cp; | |
443 | unsigned int checksum, stored_checksum; | |
444 | ||
445 | restart: | |
446 | ||
447 | /* Check if input size is less than minimum packet size. */ | |
448 | if (buffer_len(&input) < 4 + 8) | |
449 | return SSH_MSG_NONE; | |
450 | /* Get length of incoming packet. */ | |
451 | ucp = (unsigned char *)buffer_ptr(&input); | |
452 | len = GET_32BIT(ucp); | |
453 | if (len < 1 + 2 + 2 || len > 256*1024) | |
454 | packet_disconnect("Bad packet length %d.", len); | |
455 | padded_len = (len + 8) & ~7; | |
456 | ||
457 | /* Check if the packet has been entirely received. */ | |
458 | if (buffer_len(&input) < 4 + padded_len) | |
459 | return SSH_MSG_NONE; | |
460 | ||
461 | /* The entire packet is in buffer. */ | |
462 | ||
463 | /* Consume packet length. */ | |
464 | buffer_consume(&input, 4); | |
465 | ||
466 | /* Copy data to incoming_packet. */ | |
467 | buffer_clear(&incoming_packet); | |
468 | buffer_append_space(&incoming_packet, &cp, padded_len); | |
469 | packet_decrypt(&receive_context, cp, buffer_ptr(&input), padded_len); | |
470 | buffer_consume(&input, padded_len); | |
471 | ||
472 | #ifdef PACKET_DEBUG | |
473 | fprintf(stderr, "read_poll plain: "); buffer_dump(&incoming_packet); | |
474 | #endif | |
475 | ||
476 | /* Compute packet checksum. */ | |
477 | checksum = crc32((unsigned char *)buffer_ptr(&incoming_packet), | |
478 | buffer_len(&incoming_packet) - 4); | |
479 | ||
480 | /* Skip padding. */ | |
481 | buffer_consume(&incoming_packet, 8 - len % 8); | |
482 | ||
483 | /* Test check bytes. */ | |
5bae4ab8 | 484 | |
485 | if (len != buffer_len(&incoming_packet)) | |
486 | packet_disconnect("packet_read_poll: len %d != buffer_len %d.", | |
487 | len, buffer_len(&incoming_packet)); | |
488 | ||
8efc0c15 | 489 | ucp = (unsigned char *)buffer_ptr(&incoming_packet) + len - 4; |
490 | stored_checksum = GET_32BIT(ucp); | |
491 | if (checksum != stored_checksum) | |
492 | packet_disconnect("Corrupted check bytes on input."); | |
493 | buffer_consume_end(&incoming_packet, 4); | |
494 | ||
495 | /* If using packet compression, decompress the packet. */ | |
496 | if (packet_compression) | |
497 | { | |
498 | buffer_clear(&compression_buffer); | |
499 | buffer_uncompress(&incoming_packet, &compression_buffer); | |
500 | buffer_clear(&incoming_packet); | |
501 | buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), | |
502 | buffer_len(&compression_buffer)); | |
503 | } | |
504 | ||
505 | /* Get packet type. */ | |
506 | buffer_get(&incoming_packet, &buf[0], 1); | |
507 | ||
508 | /* Return length of payload (without type field). */ | |
509 | *payload_len_ptr = buffer_len(&incoming_packet); | |
510 | ||
511 | /* Handle disconnect message. */ | |
512 | if ((unsigned char)buf[0] == SSH_MSG_DISCONNECT) | |
513 | fatal("%.900s", packet_get_string(NULL)); | |
514 | ||
515 | /* Ignore ignore messages. */ | |
516 | if ((unsigned char)buf[0] == SSH_MSG_IGNORE) | |
517 | goto restart; | |
518 | ||
519 | /* Send debug messages as debugging output. */ | |
520 | if ((unsigned char)buf[0] == SSH_MSG_DEBUG) | |
521 | { | |
522 | debug("Remote: %.900s", packet_get_string(NULL)); | |
523 | goto restart; | |
524 | } | |
525 | ||
526 | /* Return type. */ | |
527 | return (unsigned char)buf[0]; | |
528 | } | |
529 | ||
530 | /* Buffers the given amount of input characters. This is intended to be | |
531 | used together with packet_read_poll. */ | |
532 | ||
533 | void | |
534 | packet_process_incoming(const char *buf, unsigned int len) | |
535 | { | |
536 | buffer_append(&input, buf, len); | |
537 | } | |
538 | ||
539 | /* Returns a character from the packet. */ | |
540 | ||
541 | unsigned int | |
542 | packet_get_char() | |
543 | { | |
544 | char ch; | |
545 | buffer_get(&incoming_packet, &ch, 1); | |
546 | return (unsigned char)ch; | |
547 | } | |
548 | ||
549 | /* Returns an integer from the packet data. */ | |
550 | ||
551 | unsigned int | |
552 | packet_get_int() | |
553 | { | |
554 | return buffer_get_int(&incoming_packet); | |
555 | } | |
556 | ||
557 | /* Returns an arbitrary precision integer from the packet data. The integer | |
558 | must have been initialized before this call. */ | |
559 | ||
560 | void | |
561 | packet_get_bignum(BIGNUM *value, int *length_ptr) | |
562 | { | |
563 | *length_ptr = buffer_get_bignum(&incoming_packet, value); | |
564 | } | |
565 | ||
566 | /* Returns a string from the packet data. The string is allocated using | |
567 | xmalloc; it is the responsibility of the calling program to free it when | |
568 | no longer needed. The length_ptr argument may be NULL, or point to an | |
569 | integer into which the length of the string is stored. */ | |
570 | ||
571 | char | |
572 | *packet_get_string(unsigned int *length_ptr) | |
573 | { | |
574 | return buffer_get_string(&incoming_packet, length_ptr); | |
575 | } | |
576 | ||
577 | /* Sends a diagnostic message from the server to the client. This message | |
578 | can be sent at any time (but not while constructing another message). | |
579 | The message is printed immediately, but only if the client is being | |
580 | executed in verbose mode. These messages are primarily intended to | |
581 | ease debugging authentication problems. The length of the formatted | |
582 | message must not exceed 1024 bytes. This will automatically call | |
583 | packet_write_wait. */ | |
584 | ||
585 | void | |
586 | packet_send_debug(const char *fmt, ...) | |
587 | { | |
588 | char buf[1024]; | |
589 | va_list args; | |
590 | ||
591 | va_start(args, fmt); | |
592 | vsnprintf(buf, sizeof(buf), fmt, args); | |
593 | va_end(args); | |
594 | ||
595 | packet_start(SSH_MSG_DEBUG); | |
596 | packet_put_string(buf, strlen(buf)); | |
597 | packet_send(); | |
598 | packet_write_wait(); | |
599 | } | |
600 | ||
601 | /* Logs the error plus constructs and sends a disconnect | |
602 | packet, closes the connection, and exits. This function never returns. | |
603 | The error message should not contain a newline. The length of the | |
604 | formatted message must not exceed 1024 bytes. */ | |
605 | ||
606 | void | |
607 | packet_disconnect(const char *fmt, ...) | |
608 | { | |
609 | char buf[1024]; | |
610 | va_list args; | |
611 | static int disconnecting = 0; | |
612 | if (disconnecting) /* Guard against recursive invocations. */ | |
613 | fatal("packet_disconnect called recursively."); | |
614 | disconnecting = 1; | |
615 | ||
616 | /* Format the message. Note that the caller must make sure the message | |
617 | is of limited size. */ | |
618 | va_start(args, fmt); | |
619 | vsnprintf(buf, sizeof(buf), fmt, args); | |
620 | va_end(args); | |
621 | ||
622 | /* Send the disconnect message to the other side, and wait for it to get | |
623 | sent. */ | |
624 | packet_start(SSH_MSG_DISCONNECT); | |
625 | packet_put_string(buf, strlen(buf)); | |
626 | packet_send(); | |
627 | packet_write_wait(); | |
628 | ||
629 | /* Stop listening for connections. */ | |
630 | channel_stop_listening(); | |
631 | ||
632 | /* Close the connection. */ | |
633 | packet_close(); | |
634 | ||
635 | /* Display the error locally and exit. */ | |
636 | fatal("Local: %.100s", buf); | |
637 | } | |
638 | ||
639 | /* Checks if there is any buffered output, and tries to write some of the | |
640 | output. */ | |
641 | ||
642 | void | |
643 | packet_write_poll() | |
644 | { | |
645 | int len = buffer_len(&output); | |
646 | if (len > 0) | |
647 | { | |
648 | len = write(connection_out, buffer_ptr(&output), len); | |
649 | if (len <= 0) { | |
650 | if (errno == EAGAIN) | |
651 | return; | |
652 | else | |
653 | fatal("Write failed: %.100s", strerror(errno)); | |
654 | } | |
655 | buffer_consume(&output, len); | |
656 | } | |
657 | } | |
658 | ||
659 | /* Calls packet_write_poll repeatedly until all pending output data has | |
660 | been written. */ | |
661 | ||
662 | void | |
663 | packet_write_wait() | |
664 | { | |
665 | packet_write_poll(); | |
666 | while (packet_have_data_to_write()) | |
667 | { | |
668 | fd_set set; | |
669 | FD_ZERO(&set); | |
670 | FD_SET(connection_out, &set); | |
671 | select(connection_out + 1, NULL, &set, NULL, NULL); | |
672 | packet_write_poll(); | |
673 | } | |
674 | } | |
675 | ||
676 | /* Returns true if there is buffered data to write to the connection. */ | |
677 | ||
678 | int | |
679 | packet_have_data_to_write() | |
680 | { | |
681 | return buffer_len(&output) != 0; | |
682 | } | |
683 | ||
684 | /* Returns true if there is not too much data to write to the connection. */ | |
685 | ||
686 | int | |
687 | packet_not_very_much_data_to_write() | |
688 | { | |
689 | if (interactive_mode) | |
690 | return buffer_len(&output) < 16384; | |
691 | else | |
692 | return buffer_len(&output) < 128*1024; | |
693 | } | |
694 | ||
695 | /* Informs that the current session is interactive. Sets IP flags for that. */ | |
696 | ||
697 | void | |
698 | packet_set_interactive(int interactive, int keepalives) | |
699 | { | |
700 | int on = 1; | |
701 | ||
702 | /* Record that we are in interactive mode. */ | |
703 | interactive_mode = interactive; | |
704 | ||
705 | /* Only set socket options if using a socket (as indicated by the descriptors | |
706 | being the same). */ | |
707 | if (connection_in != connection_out) | |
708 | return; | |
709 | ||
710 | if (keepalives) | |
711 | { | |
712 | /* Set keepalives if requested. */ | |
713 | if (setsockopt(connection_in, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, | |
714 | sizeof(on)) < 0) | |
715 | error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); | |
716 | } | |
717 | ||
718 | if (interactive) | |
719 | { | |
720 | /* Set IP options for an interactive connection. Use IPTOS_LOWDELAY | |
721 | and TCP_NODELAY. */ | |
722 | int lowdelay = IPTOS_LOWDELAY; | |
723 | if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *)&lowdelay, | |
724 | sizeof(lowdelay)) < 0) | |
725 | error("setsockopt IPTOS_LOWDELAY: %.100s", strerror(errno)); | |
726 | if (setsockopt(connection_in, IPPROTO_TCP, TCP_NODELAY, (void *)&on, | |
727 | sizeof(on)) < 0) | |
728 | error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); | |
729 | } | |
730 | else | |
731 | { | |
732 | /* Set IP options for a non-interactive connection. Use | |
733 | IPTOS_THROUGHPUT. */ | |
734 | int throughput = IPTOS_THROUGHPUT; | |
735 | if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *)&throughput, | |
736 | sizeof(throughput)) < 0) | |
737 | error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno)); | |
738 | } | |
739 | } | |
740 | ||
741 | /* Returns true if the current connection is interactive. */ | |
742 | ||
743 | int | |
744 | packet_is_interactive() | |
745 | { | |
746 | return interactive_mode; | |
747 | } |