⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 packet.c

📁 OpenSSH 是 SSH (Secure SHell) 协议的免费开源实现。它用安全、加密的网络连接工具代替了 telnet、ftp、 rlogin、rsh 和 rcp 工具。OpenSSH 支持
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland *                    All rights reserved * This file contains code implementing the packet protocol and communication * with the other side.  This same code is used both on client and server side. * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose.  Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". * * * SSH2 packet format added by Markus Friedl. * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "includes.h"RCSID("$OpenBSD: packet.c,v 1.116 2004/10/20 11:48:53 markus Exp $");#include "openbsd-compat/sys-queue.h"#include "xmalloc.h"#include "buffer.h"#include "packet.h"#include "bufaux.h"#include "crc32.h"#include "getput.h"#include "compress.h"#include "deattack.h"#include "channels.h"#include "compat.h"#include "ssh1.h"#include "ssh2.h"#include "cipher.h"#include "kex.h"#include "mac.h"#include "log.h"#include "canohost.h"#include "misc.h"#include "ssh.h"#ifdef PACKET_DEBUG#define DBG(x) x#else#define DBG(x)#endif/* * This variable contains the file descriptors used for communicating with * the other side.  connection_in is used for reading; connection_out for * writing.  These can be the same descriptor, in which case it is assumed to * be a socket. */static int connection_in = -1;static int connection_out = -1;/* Protocol flags for the remote side. */static u_int remote_protocol_flags = 0;/* Encryption context for receiving data.  This is only used for decryption. */static CipherContext receive_context;/* Encryption context for sending data.  This is only used for encryption. */static CipherContext send_context;/* Buffer for raw input data from the socket. */Buffer input;/* Buffer for raw output data going to the socket. */Buffer output;/* Buffer for the partial outgoing packet being constructed. */static Buffer outgoing_packet;/* Buffer for the incoming packet currently being processed. */static Buffer incoming_packet;/* Scratch buffer for packet compression/decompression. */static Buffer compression_buffer;static int compression_buffer_ready = 0;/* Flag indicating whether packet compression/decompression is enabled. */static int packet_compression = 0;/* default maximum packet size */u_int max_packet_size = 32768;/* Flag indicating whether this module has been initialized. */static int initialized = 0;/* Set to true if the connection is interactive. */static int interactive_mode = 0;/* Session key information for Encryption and MAC */Newkeys *newkeys[MODE_MAX];static struct packet_state {	u_int32_t seqnr;	u_int32_t packets;	u_int64_t blocks;} p_read, p_send;static u_int64_t max_blocks_in, max_blocks_out;static u_int32_t rekey_limit;/* Session key for protocol v1 */static u_char ssh1_key[SSH_SESSION_KEY_LENGTH];static u_int ssh1_keylen;/* roundup current message to extra_pad bytes */static u_char extra_pad = 0;struct packet {	TAILQ_ENTRY(packet) next;	u_char type;	Buffer payload;};TAILQ_HEAD(, packet) outgoing;/* * Sets the descriptors used for communication.  Disables encryption until * packet_set_encryption_key is called. */voidpacket_set_connection(int fd_in, int fd_out){	Cipher *none = cipher_by_name("none");	if (none == NULL)		fatal("packet_set_connection: cannot load cipher 'none'");	connection_in = fd_in;	connection_out = fd_out;	cipher_init(&send_context, none, (const u_char *)"",	    0, NULL, 0, CIPHER_ENCRYPT);	cipher_init(&receive_context, none, (const u_char *)"",	    0, NULL, 0, CIPHER_DECRYPT);	newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL;	if (!initialized) {		initialized = 1;		buffer_init(&input);		buffer_init(&output);		buffer_init(&outgoing_packet);		buffer_init(&incoming_packet);		TAILQ_INIT(&outgoing);	}}/* Returns 1 if remote host is connected via socket, 0 if not. */intpacket_connection_is_on_socket(void){	struct sockaddr_storage from, to;	socklen_t fromlen, tolen;	/* filedescriptors in and out are the same, so it's a socket */	if (connection_in == connection_out)		return 1;	fromlen = sizeof(from);	memset(&from, 0, sizeof(from));	if (getpeername(connection_in, (struct sockaddr *)&from, &fromlen) < 0)		return 0;	tolen = sizeof(to);	memset(&to, 0, sizeof(to));	if (getpeername(connection_out, (struct sockaddr *)&to, &tolen) < 0)		return 0;	if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0)		return 0;	if (from.ss_family != AF_INET && from.ss_family != AF_INET6)		return 0;	return 1;}/* * Exports an IV from the CipherContext required to export the key * state back from the unprivileged child to the privileged parent * process. */voidpacket_get_keyiv(int mode, u_char *iv, u_int len){	CipherContext *cc;	if (mode == MODE_OUT)		cc = &send_context;	else		cc = &receive_context;	cipher_get_keyiv(cc, iv, len);}intpacket_get_keycontext(int mode, u_char *dat){	CipherContext *cc;	if (mode == MODE_OUT)		cc = &send_context;	else		cc = &receive_context;	return (cipher_get_keycontext(cc, dat));}voidpacket_set_keycontext(int mode, u_char *dat){	CipherContext *cc;	if (mode == MODE_OUT)		cc = &send_context;	else		cc = &receive_context;	cipher_set_keycontext(cc, dat);}intpacket_get_keyiv_len(int mode){	CipherContext *cc;	if (mode == MODE_OUT)		cc = &send_context;	else		cc = &receive_context;	return (cipher_get_keyiv_len(cc));}voidpacket_set_iv(int mode, u_char *dat){	CipherContext *cc;	if (mode == MODE_OUT)		cc = &send_context;	else		cc = &receive_context;	cipher_set_keyiv(cc, dat);}intpacket_get_ssh1_cipher(void){	return (cipher_get_number(receive_context.cipher));}voidpacket_get_state(int mode, u_int32_t *seqnr, u_int64_t *blocks, u_int32_t *packets){	struct packet_state *state;	state = (mode == MODE_IN) ? &p_read : &p_send;	*seqnr = state->seqnr;	*blocks = state->blocks;	*packets = state->packets;}voidpacket_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets){	struct packet_state *state;	state = (mode == MODE_IN) ? &p_read : &p_send;	state->seqnr = seqnr;	state->blocks = blocks;	state->packets = packets;}/* returns 1 if connection is via ipv4 */intpacket_connection_is_ipv4(void){	struct sockaddr_storage to;	socklen_t tolen = sizeof(to);	memset(&to, 0, sizeof(to));	if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0)		return 0;	if (to.ss_family == AF_INET)		return 1;#ifdef IPV4_IN_IPV6	if (to.ss_family == AF_INET6 &&	    IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&to)->sin6_addr))		return 1;#endif	return 0;}/* Sets the connection into non-blocking mode. */voidpacket_set_nonblocking(void){	/* Set the socket into non-blocking mode. */	set_nonblock(connection_in);	if (connection_out != connection_in)		set_nonblock(connection_out);}/* Returns the socket used for reading. */intpacket_get_connection_in(void){	return connection_in;}/* Returns the descriptor used for writing. */intpacket_get_connection_out(void){	return connection_out;}/* Closes the connection and clears and frees internal data structures. */voidpacket_close(void){	if (!initialized)		return;	initialized = 0;	if (connection_in == connection_out) {		shutdown(connection_out, SHUT_RDWR);		close(connection_out);	} else {		close(connection_in);		close(connection_out);	}	buffer_free(&input);	buffer_free(&output);	buffer_free(&outgoing_packet);	buffer_free(&incoming_packet);	if (compression_buffer_ready) {		buffer_free(&compression_buffer);		buffer_compress_uninit();	}	cipher_cleanup(&send_context);	cipher_cleanup(&receive_context);}/* Sets remote side protocol flags. */voidpacket_set_protocol_flags(u_int protocol_flags){	remote_protocol_flags = protocol_flags;}/* Returns the remote protocol flags set earlier by the above function. */u_intpacket_get_protocol_flags(void){	return remote_protocol_flags;}/* * Starts packet compression from the next packet on in both directions. * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. */static voidpacket_init_compression(void){	if (compression_buffer_ready == 1)		return;	compression_buffer_ready = 1;	buffer_init(&compression_buffer);}voidpacket_start_compression(int level){	if (packet_compression && !compat20)		fatal("Compression already enabled.");	packet_compression = 1;	packet_init_compression();	buffer_compress_init_send(level);	buffer_compress_init_recv();}/* * Causes any further packets to be encrypted using the given key.  The same * key is used for both sending and reception.  However, both directions are * encrypted independently of each other. */voidpacket_set_encryption_key(const u_char *key, u_int keylen,    int number){	Cipher *cipher = cipher_by_number(number);	if (cipher == NULL)		fatal("packet_set_encryption_key: unknown cipher number %d", number);	if (keylen < 20)		fatal("packet_set_encryption_key: keylen too small: %d", keylen);	if (keylen > SSH_SESSION_KEY_LENGTH)		fatal("packet_set_encryption_key: keylen too big: %d", keylen);	memcpy(ssh1_key, key, keylen);	ssh1_keylen = keylen;	cipher_init(&send_context, cipher, key, keylen, NULL, 0, CIPHER_ENCRYPT);	cipher_init(&receive_context, cipher, key, keylen, NULL, 0, CIPHER_DECRYPT);}u_intpacket_get_encryption_key(u_char *key){	if (key == NULL)		return (ssh1_keylen);	memcpy(key, ssh1_key, ssh1_keylen);	return (ssh1_keylen);}/* Start constructing a packet to send. */voidpacket_start(u_char type){	u_char buf[9];	int len;	DBG(debug("packet_start[%d]", type));	len = compat20 ? 6 : 9;	memset(buf, 0, len - 1);	buf[len - 1] = type;	buffer_clear(&outgoing_packet);	buffer_append(&outgoing_packet, buf, len);}/* Append payload. */voidpacket_put_char(int value){	char ch = value;	buffer_append(&outgoing_packet, &ch, 1);}voidpacket_put_int(u_int value){	buffer_put_int(&outgoing_packet, value);}voidpacket_put_string(const void *buf, u_int len){	buffer_put_string(&outgoing_packet, buf, len);}voidpacket_put_cstring(const char *str){	buffer_put_cstring(&outgoing_packet, str);}voidpacket_put_raw(const void *buf, u_int len){	buffer_append(&outgoing_packet, buf, len);}voidpacket_put_bignum(BIGNUM * value){	buffer_put_bignum(&outgoing_packet, value);}voidpacket_put_bignum2(BIGNUM * value){	buffer_put_bignum2(&outgoing_packet, value);}/* * Finalizes and sends the packet.  If the encryption key has been set, * encrypts the packet before sending. */static voidpacket_send1(void){	u_char buf[8], *cp;	int i, padding, len;	u_int checksum;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -