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