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