📄 packet.c
字号:
need, block_size, need % block_size); /* * check if the entire packet has been received and * decrypt into incoming_packet */ if (buffer_len(&input) < need + maclen) return SSH_MSG_NONE;#ifdef PACKET_DEBUG fprintf(stderr, "read_poll enc/full: "); buffer_dump(&input);#endif cp = buffer_append_space(&incoming_packet, need); cipher_crypt(&receive_context, cp, buffer_ptr(&input), need); buffer_consume(&input, need); /* * compute MAC over seqnr and packet, * increment sequence number for incoming packet */ if (mac && mac->enabled) { macbuf = mac_compute(mac, read_seqnr, buffer_ptr(&incoming_packet), buffer_len(&incoming_packet)); if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) packet_disconnect("Corrupted MAC on input."); DBG(debug("MAC #%d ok", read_seqnr)); buffer_consume(&input, mac->mac_len); } if (seqnr_p != NULL) *seqnr_p = read_seqnr; if (++read_seqnr == 0) log("incoming seqnr wraps around"); /* get padlen */ cp = buffer_ptr(&incoming_packet); padlen = cp[4]; DBG(debug("input: padlen %d", padlen)); if (padlen < 4) packet_disconnect("Corrupted padlen %d on input.", padlen); /* skip packet size + padlen, discard padding */ buffer_consume(&incoming_packet, 4 + 1); buffer_consume_end(&incoming_packet, padlen); DBG(debug("input: len before de-compress %d", buffer_len(&incoming_packet))); if (comp && comp->enabled) { buffer_clear(&compression_buffer); buffer_uncompress(&incoming_packet, &compression_buffer); buffer_clear(&incoming_packet); buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), buffer_len(&compression_buffer)); DBG(debug("input: len after de-compress %d", buffer_len(&incoming_packet))); } /* * get packet type, implies consume. * return length of payload (without type field) */ type = buffer_get_char(&incoming_packet); if (type == SSH2_MSG_NEWKEYS) set_newkeys(MODE_IN);#ifdef PACKET_DEBUG fprintf(stderr, "read/plain[%d]:\r\n", type); buffer_dump(&incoming_packet);#endif /* reset for next packet */ packet_length = 0; return type;}intpacket_read_poll_seqnr(u_int32_t *seqnr_p){ int reason, seqnr; u_char type; char *msg; for (;;) { if (compat20) { type = packet_read_poll2(seqnr_p); if (type) DBG(debug("received packet type %d", type)); switch (type) { case SSH2_MSG_IGNORE: break; case SSH2_MSG_DEBUG: packet_get_char(); msg = packet_get_string(NULL); debug("Remote: %.900s", msg); xfree(msg); msg = packet_get_string(NULL); xfree(msg); break; case SSH2_MSG_DISCONNECT: reason = packet_get_int(); msg = packet_get_string(NULL); log("Received disconnect from %s: %d: %.400s", get_remote_ipaddr(), reason, msg); xfree(msg); fatal_cleanup(); break; case SSH2_MSG_UNIMPLEMENTED: seqnr = packet_get_int(); debug("Received SSH2_MSG_UNIMPLEMENTED for %d", seqnr); break; default: return type; break; } } else { type = packet_read_poll1(); switch (type) { case SSH_MSG_IGNORE: break; case SSH_MSG_DEBUG: msg = packet_get_string(NULL); debug("Remote: %.900s", msg); xfree(msg); break; case SSH_MSG_DISCONNECT: msg = packet_get_string(NULL); log("Received disconnect from %s: %.400s", get_remote_ipaddr(), msg); fatal_cleanup(); xfree(msg); break; default: if (type) DBG(debug("received packet type %d", type)); return type; break; } } }}intpacket_read_poll(void){ return packet_read_poll_seqnr(NULL);}/* * Buffers the given amount of input characters. This is intended to be used * together with packet_read_poll. */voidpacket_process_incoming(const char *buf, u_int len){ buffer_append(&input, buf, len);}/* Returns a character from the packet. */u_intpacket_get_char(void){ char ch; buffer_get(&incoming_packet, &ch, 1); return (u_char) ch;}/* Returns an integer from the packet data. */u_intpacket_get_int(void){ return buffer_get_int(&incoming_packet);}/* * Returns an arbitrary precision integer from the packet data. The integer * must have been initialized before this call. */voidpacket_get_bignum(BIGNUM * value){ buffer_get_bignum(&incoming_packet, value);}voidpacket_get_bignum2(BIGNUM * value){ buffer_get_bignum2(&incoming_packet, value);}void *packet_get_raw(int *length_ptr){ int bytes = buffer_len(&incoming_packet); if (length_ptr != NULL) *length_ptr = bytes; return buffer_ptr(&incoming_packet);}intpacket_remaining(void){ return buffer_len(&incoming_packet);}/* * Returns a string from the packet data. The string is allocated using * xmalloc; it is the responsibility of the calling program to free it when * no longer needed. The length_ptr argument may be NULL, or point to an * integer into which the length of the string is stored. */void *packet_get_string(u_int *length_ptr){ return buffer_get_string(&incoming_packet, length_ptr);}/* * Sends a diagnostic message from the server to the client. This message * can be sent at any time (but not while constructing another message). The * message is printed immediately, but only if the client is being executed * in verbose mode. These messages are primarily intended to ease debugging * authentication problems. The length of the formatted message must not * exceed 1024 bytes. This will automatically call packet_write_wait. */voidpacket_send_debug(const char *fmt,...){ char buf[1024]; va_list args; if (compat20 && (datafellows & SSH_BUG_DEBUG)) return; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); if (compat20) { packet_start(SSH2_MSG_DEBUG); packet_put_char(0); /* bool: always display */ packet_put_cstring(buf); packet_put_cstring(""); } else { packet_start(SSH_MSG_DEBUG); packet_put_cstring(buf); } packet_send(); packet_write_wait();}/* * Logs the error plus constructs and sends a disconnect packet, closes the * connection, and exits. This function never returns. The error message * should not contain a newline. The length of the formatted message must * not exceed 1024 bytes. */voidpacket_disconnect(const char *fmt,...){ char buf[1024]; va_list args; static int disconnecting = 0; if (disconnecting) /* Guard against recursive invocations. */ fatal("packet_disconnect called recursively."); disconnecting = 1; /* * Format the message. Note that the caller must make sure the * message is of limited size. */ va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); /* Send the disconnect message to the other side, and wait for it to get sent. */ if (compat20) { packet_start(SSH2_MSG_DISCONNECT); packet_put_int(SSH2_DISCONNECT_PROTOCOL_ERROR); packet_put_cstring(buf); packet_put_cstring(""); } else { packet_start(SSH_MSG_DISCONNECT); packet_put_cstring(buf); } packet_send(); packet_write_wait(); /* Stop listening for connections. */ channel_close_all(); /* Close the connection. */ packet_close(); /* Display the error locally and exit. */ log("Disconnecting: %.100s", buf); fatal_cleanup();}/* Checks if there is any buffered output, and tries to write some of the output. */voidpacket_write_poll(void){ int len = buffer_len(&output); if (len > 0) { len = write(connection_out, buffer_ptr(&output), len); if (len <= 0) { if (errno == EAGAIN) return; else fatal("Write failed: %.100s", strerror(errno)); } buffer_consume(&output, len); }}/* * Calls packet_write_poll repeatedly until all pending output data has been * written. */voidpacket_write_wait(void){ fd_set *setp; setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) * sizeof(fd_mask)); packet_write_poll(); while (packet_have_data_to_write()) { memset(setp, 0, howmany(connection_out + 1, NFDBITS) * sizeof(fd_mask)); FD_SET(connection_out, setp); while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 && (errno == EAGAIN || errno == EINTR)) ; packet_write_poll(); } xfree(setp);}/* Returns true if there is buffered data to write to the connection. */intpacket_have_data_to_write(void){ return buffer_len(&output) != 0;}/* Returns true if there is not too much data to write to the connection. */intpacket_not_very_much_data_to_write(void){ if (interactive_mode) return buffer_len(&output) < 16384; else return buffer_len(&output) < 128 * 1024;}/* Informs that the current session is interactive. Sets IP flags for that. */voidpacket_set_interactive(int interactive){ static int called = 0;#if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN) int lowdelay = IPTOS_LOWDELAY; int throughput = IPTOS_THROUGHPUT;#endif if (called) return; called = 1; /* Record that we are in interactive mode. */ interactive_mode = interactive; /* Only set socket options if using a socket. */ if (!packet_connection_is_on_socket()) return; /* * IPTOS_LOWDELAY and IPTOS_THROUGHPUT are IPv4 only */ if (interactive) { /* * Set IP options for an interactive connection. Use * IPTOS_LOWDELAY and TCP_NODELAY. */#if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN) if (packet_connection_is_ipv4()) { if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &lowdelay, sizeof(lowdelay)) < 0) error("setsockopt IPTOS_LOWDELAY: %.100s", strerror(errno)); }#endif set_nodelay(connection_in); } else if (packet_connection_is_ipv4()) { /* * Set IP options for a non-interactive connection. Use * IPTOS_THROUGHPUT. */#if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN) if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &throughput, sizeof(throughput)) < 0) error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));#endif }}/* Returns true if the current connection is interactive. */intpacket_is_interactive(void){ return interactive_mode;}intpacket_set_maxsize(int s){ static int called = 0; if (called) { log("packet_set_maxsize: called twice: old %d new %d", max_packet_size, s); return -1; } if (s < 4 * 1024 || s > 1024 * 1024) { log("packet_set_maxsize: bad size %d", s); return -1; } called = 1; debug("packet_set_maxsize: setting to %d", s); max_packet_size = s; return s;}/* roundup current message to pad bytes */voidpacket_add_padding(u_char pad){ extra_pad = pad;}/* * 9.2. Ignored Data Message * * byte SSH_MSG_IGNORE * string data * * All implementations MUST understand (and ignore) this message at any * time (after receiving the protocol version). No implementation is * required to send them. This message can be used as an additional * protection measure against advanced traffic analysis techniques. */voidpacket_send_ignore(int nbytes){ u_int32_t rand = 0; int i; packet_start(compat20 ? SSH2_MSG_IGNORE : SSH_MSG_IGNORE); packet_put_int(nbytes); for (i = 0; i < nbytes; i++) { if (i % 4 == 0) rand = arc4random(); packet_put_char(rand & 0xff); rand >>= 8; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -