fixed uTP vulnerability
This commit is contained in:
parent
2fee484edd
commit
4d89c7da97
|
@ -74,6 +74,7 @@
|
||||||
|
|
||||||
1.0.6 release
|
1.0.6 release
|
||||||
|
|
||||||
|
* fixed uTP vulnerability
|
||||||
* make utf8 conversions more lenient
|
* make utf8 conversions more lenient
|
||||||
* fix loading of piece priorities from resume data
|
* fix loading of piece priorities from resume data
|
||||||
* improved seed-mode handling (seed-mode will now automatically be left when
|
* improved seed-mode handling (seed-mode will now automatically be left when
|
||||||
|
|
|
@ -308,7 +308,7 @@ namespace libtorrent
|
||||||
SET(utp_min_timeout, 500, 0),
|
SET(utp_min_timeout, 500, 0),
|
||||||
SET(utp_syn_resends, 2, 0),
|
SET(utp_syn_resends, 2, 0),
|
||||||
SET(utp_fin_resends, 2, 0),
|
SET(utp_fin_resends, 2, 0),
|
||||||
SET(utp_num_resends, 6, 0),
|
SET(utp_num_resends, 3, 0),
|
||||||
SET(utp_connect_timeout, 3000, 0),
|
SET(utp_connect_timeout, 3000, 0),
|
||||||
SET(utp_delayed_ack, 0, 0),
|
SET(utp_delayed_ack, 0, 0),
|
||||||
SET(utp_loss_multiplier, 50, 0),
|
SET(utp_loss_multiplier, 50, 0),
|
||||||
|
|
|
@ -280,6 +280,7 @@ struct utp_socket_impl
|
||||||
, m_deferred_ack(false)
|
, m_deferred_ack(false)
|
||||||
, m_subscribe_drained(false)
|
, m_subscribe_drained(false)
|
||||||
, m_stalled(false)
|
, m_stalled(false)
|
||||||
|
, m_confirmed(false)
|
||||||
{
|
{
|
||||||
m_sm->inc_stats_counter(counters::num_utp_idle);
|
m_sm->inc_stats_counter(counters::num_utp_idle);
|
||||||
TORRENT_ASSERT(m_userdata);
|
TORRENT_ASSERT(m_userdata);
|
||||||
|
@ -405,7 +406,7 @@ public:
|
||||||
// refer to the unwritten portions of the buffers, and the
|
// refer to the unwritten portions of the buffers, and the
|
||||||
// ones that fill up are erased from the vector
|
// ones that fill up are erased from the vector
|
||||||
std::vector<iovec_t> m_read_buffer;
|
std::vector<iovec_t> m_read_buffer;
|
||||||
|
|
||||||
// packets we've received without a read operation
|
// packets we've received without a read operation
|
||||||
// active. Store them here until the client triggers
|
// active. Store them here until the client triggers
|
||||||
// an async_read_some
|
// an async_read_some
|
||||||
|
@ -491,7 +492,7 @@ public:
|
||||||
|
|
||||||
// the sum of all packets stored in m_receive_buffer
|
// the sum of all packets stored in m_receive_buffer
|
||||||
boost::int32_t m_receive_buffer_size;
|
boost::int32_t m_receive_buffer_size;
|
||||||
|
|
||||||
// the sum of all buffers in m_read_buffer
|
// the sum of all buffers in m_read_buffer
|
||||||
boost::int32_t m_read_buffer_size;
|
boost::int32_t m_read_buffer_size;
|
||||||
|
|
||||||
|
@ -675,6 +676,11 @@ public:
|
||||||
// of sockets in the utp_socket_manager to be notified of
|
// of sockets in the utp_socket_manager to be notified of
|
||||||
// the socket being writable again
|
// the socket being writable again
|
||||||
bool m_stalled:1;
|
bool m_stalled:1;
|
||||||
|
|
||||||
|
// this is false by default and set to true once we've received a non-SYN
|
||||||
|
// packet for this connection with a correct ack_nr, confirming that the
|
||||||
|
// other end is not spoofing its source IP
|
||||||
|
bool m_confirmed:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
utp_socket_impl* construct_utp_impl(boost::uint16_t recv_id
|
utp_socket_impl* construct_utp_impl(boost::uint16_t recv_id
|
||||||
|
@ -2736,11 +2742,14 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
||||||
if (m_state == UTP_STATE_SYN_SENT && ph->get_type() == ST_STATE)
|
if (m_state == UTP_STATE_SYN_SENT && ph->get_type() == ST_STATE)
|
||||||
cmp_seq_nr = m_seq_nr;
|
cmp_seq_nr = m_seq_nr;
|
||||||
#endif
|
#endif
|
||||||
if (m_state != UTP_STATE_NONE
|
if ((m_state != UTP_STATE_NONE || ph->get_type() != ST_SYN)
|
||||||
&& compare_less_wrap(cmp_seq_nr, ph->ack_nr, ACK_MASK))
|
&& (compare_less_wrap(cmp_seq_nr, ph->ack_nr, ACK_MASK)
|
||||||
|
|| compare_less_wrap(ph->ack_nr, m_acked_seq_nr
|
||||||
|
- dup_ack_limit, ACK_MASK)))
|
||||||
{
|
{
|
||||||
UTP_LOG("%8p: ERROR: incoming packet ack_nr:%d our seq_nr:%d (ignored)\n"
|
UTP_LOG("%8p: ERROR: incoming packet ack_nr:%d our seq_nr:%d our "
|
||||||
, this, int(ph->ack_nr), m_seq_nr);
|
"acked_seq_nr:%d (ignored)\n"
|
||||||
|
, this, int(ph->ack_nr), m_seq_nr, m_acked_seq_nr);
|
||||||
m_sm->inc_stats_counter(counters::utp_redundant_pkts_in);
|
m_sm->inc_stats_counter(counters::utp_redundant_pkts_in);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2805,12 +2814,6 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
||||||
, this, int(ph->ack_nr), m_seq_nr);
|
, this, int(ph->ack_nr), m_seq_nr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (compare_less_wrap(ph->ack_nr, m_acked_seq_nr , ACK_MASK))
|
|
||||||
{
|
|
||||||
UTP_LOG("%8p: ERROR: invalid RESET packet, ack_nr:%d our acked_seq_nr:%d (ignored)\n"
|
|
||||||
, this, int(ph->ack_nr), m_acked_seq_nr);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
UTP_LOGV("%8p: incoming packet type:RESET\n", this);
|
UTP_LOGV("%8p: incoming packet type:RESET\n", this);
|
||||||
m_error = boost::asio::error::connection_reset;
|
m_error = boost::asio::error::connection_reset;
|
||||||
set_state(UTP_STATE_ERROR_WAIT);
|
set_state(UTP_STATE_ERROR_WAIT);
|
||||||
|
@ -2927,7 +2930,7 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
||||||
ptr += len;
|
ptr += len;
|
||||||
extension = next_extension;
|
extension = next_extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the send operation in parse_sack() may have set the socket to an error
|
// the send operation in parse_sack() may have set the socket to an error
|
||||||
// state, in which case we shouldn't continue
|
// state, in which case we shouldn't continue
|
||||||
if (m_state == UTP_STATE_ERROR_WAIT || m_state == UTP_STATE_DELETE) return true;
|
if (m_state == UTP_STATE_ERROR_WAIT || m_state == UTP_STATE_DELETE) return true;
|
||||||
|
@ -3118,6 +3121,10 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
||||||
bool has_ack = ph->get_type() == ST_DATA || ph->get_type() == ST_FIN || ph->get_type() == ST_SYN;
|
bool has_ack = ph->get_type() == ST_DATA || ph->get_type() == ST_FIN || ph->get_type() == ST_SYN;
|
||||||
boost::uint32_t prev_out_packets = m_out_packets;
|
boost::uint32_t prev_out_packets = m_out_packets;
|
||||||
|
|
||||||
|
// the connection is connected and this packet made it past all the
|
||||||
|
// checks. We can now assume the other end is not spoofing it's IP.
|
||||||
|
if (ph->get_type() != ST_SYN) m_confirmed = true;
|
||||||
|
|
||||||
// try to send more data as long as we can
|
// try to send more data as long as we can
|
||||||
// if send_pkt returns true
|
// if send_pkt returns true
|
||||||
while (send_pkt());
|
while (send_pkt());
|
||||||
|
@ -3504,7 +3511,10 @@ void utp_socket_impl::tick(time_point now)
|
||||||
|
|
||||||
if (m_outbuf.size()) ++m_num_timeouts;
|
if (m_outbuf.size()) ++m_num_timeouts;
|
||||||
|
|
||||||
if (m_num_timeouts > m_sm->num_resends())
|
// a socket that has not been confirmed to actually have a live remote end
|
||||||
|
// (the IP may have been spoofed) fail on the first timeout. If we had
|
||||||
|
// heard anything from this peer, it would have been confirmed.
|
||||||
|
if (m_num_timeouts > m_sm->num_resends() || !m_confirmed)
|
||||||
{
|
{
|
||||||
// the connection is dead
|
// the connection is dead
|
||||||
m_error = boost::asio::error::timed_out;
|
m_error = boost::asio::error::timed_out;
|
||||||
|
@ -3541,7 +3551,7 @@ void utp_socket_impl::tick(time_point now)
|
||||||
TORRENT_ASSERT(m_cwnd >= 0);
|
TORRENT_ASSERT(m_cwnd >= 0);
|
||||||
|
|
||||||
m_timeout = now + milliseconds(packet_timeout());
|
m_timeout = now + milliseconds(packet_timeout());
|
||||||
|
|
||||||
UTP_LOGV("%8p: timeout resetting cwnd:%d\n"
|
UTP_LOGV("%8p: timeout resetting cwnd:%d\n"
|
||||||
, this, int(m_cwnd >> 16));
|
, this, int(m_cwnd >> 16));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue