1.1. Rationale
---------------------------------------
-The application uses ICMP echo requests messages, or TCP segments to verify
-whether a given host is available (up) or not (down).
+The application uses ICMP echo requests messages, or TCP SYN segments, to
+verify whether a given host is available (up) or not (down).
The host's address can be an IP or a DNS.
[3] http://en.wikipedia.org/wiki/Internet_Control_Message_Protocol
[4] http://www.boost.org/doc/libs/1_45_0/doc/html/boost_asio.html
[5] http://www.boost.org/doc/libs/1_45_0/doc/html/program_options.html
-[6] http://www.networkuptime.com/nmap/page4-4.shtml
+[6] http://www.networkuptime.com/nmap/page4-5.shtml
}
/**
+ * @brief Convenience method to check if this segment, matching the arguments,
+ * is a SYN/ACK reply.
+ *
+ * @param source_address The source address.
+ *
+ * @return @c true if this packet is a SYN/ACK reply, or @c false otherwise.
+ */
+bool TcpIpv4Segment::match_syn_ack_reply(
+ const address &source_address
+) const
+{
+ BOOST_ASSERT( source_address.is_v4() );
+
+ Ipv4Header ipv4_header = get_ip_header();
+ TcpHeader tcp_header = get_tcp_header();
+
+ bool match_synchronize = tcp_header.get_synchronize();
+ bool match_acknowledgment = tcp_header.get_acknowledgment();
+ bool match_address = ipv4_header.get_source_address() == source_address;
+
+ return ( match_synchronize && match_acknowledgment && match_address );
+}
+
+/**
+ * @brief Prints the SYN/ACK reply.
+ *
+ * @param time_segment_sent The time when this segment was sent.
+ *
+ * @return void
+ */
+void TcpIpv4Segment::print_syn_ack_reply(
+ const ptime &time_segment_sent
+) const
+{
+ Ipv4Header ipv4_header = get_ip_header();
+ TcpHeader tcp_header = get_tcp_header();
+
+ uint32_t sequence_number = tcp_header.get_sequence_number();
+ int ttl = ipv4_header.get_time_to_live();
+ ptime now = microsec_clock::universal_time();
+ time_resolution_traits_adapted64_impl::int_type elapsed_time =
+ (now - time_segment_sent).total_milliseconds();
+
+ GlobalLogger.info() << "SYN/ACK from " << ipv4_header.get_source_address()
+ << ": tcp_seq=" << sequence_number
+ << ", ttl=" << ttl
+ << " time=" << elapsed_time << " ms"
+ << endl;
+}
+
+/**
* @brief Read the TCP Segment from the @c istream.
*
* @param is The input stream.
const boost::posix_time::ptime &time_segment_sent
) const;
+ virtual bool match_syn_ack_reply(
+ const boost::asio::ip::address &source_address
+ ) const;
+
+ virtual void print_syn_ack_reply(
+ const boost::posix_time::ptime &time_packet_sent
+ ) const;
+
virtual bool read( std::istream &is );
virtual bool write( std::ostream &os ) const;
}
/**
+ * @brief Convenience method to check if this segment, matching the arguments,
+ * is a SYN/ACK reply.
+ *
+ * @param source_address The source address.
+ *
+ * @return @c true if this packet is a SYN/ACK reply, or @c false otherwise.
+ */
+bool TcpIpv6Segment::match_syn_ack_reply(
+ const address &source_address
+) const
+{
+ BOOST_ASSERT( source_address.is_v6() );
+
+ Ipv6Header ipv6_header = get_ip_header();
+ TcpHeader tcp_header = get_tcp_header();
+
+ bool match_synchronize = tcp_header.get_synchronize();
+ bool match_acknowledgment = tcp_header.get_acknowledgment();
+ bool match_address = ipv6_header.get_source_address() == source_address;
+
+ return ( match_synchronize && match_acknowledgment && match_address );
+}
+
+/**
+ * @brief Prints the SYN/ACK reply.
+ *
+ * @param time_segment_sent The time when this segment was sent.
+ *
+ * @return void
+ */
+void TcpIpv6Segment::print_syn_ack_reply(
+ const ptime &time_segment_sent
+) const
+{
+ Ipv6Header ipv6_header = get_ip_header();
+ TcpHeader tcp_header = get_tcp_header();
+
+ uint32_t sequence_number = tcp_header.get_sequence_number();
+ int hops = ipv6_header.get_hop_limit();
+ ptime now = microsec_clock::universal_time();
+ time_resolution_traits_adapted64_impl::int_type elapsed_time =
+ (now - time_segment_sent).total_milliseconds();
+
+ GlobalLogger.info() << "SYN/ACK from " << ipv6_header.get_source_address()
+ << ": tcp_seq=" << sequence_number
+ << ", hops=" << hops
+ << " time=" << elapsed_time << " ms"
+ << endl;
+}
+
+/**
* @brief Read the TCP Segment from the @c istream.
*
* @param is The input stream.
const boost::posix_time::ptime &time_segment_sent
) const;
+ virtual bool match_syn_ack_reply(
+ const boost::asio::ip::address &source_address
+ ) const;
+
+ virtual void print_syn_ack_reply(
+ const boost::posix_time::ptime &time_packet_sent
+ ) const;
+
virtual bool read( std::istream &is );
virtual bool write( std::ostream &os ) const;
{
++SequenceNumber;
- // Create a TCP header for an ACK request.
+ // Create a TCP header for a SYN request.
address source_address = get_source_address();
address destination_address = get_destination_address();
uint16_t source_port = get_source_port();
uint16_t destination_port = get_destination_port();
- TcpSegmentItem tcp_segment = TcpSegmentFactory::create_tcp_segment_ack_request(
+ TcpSegmentItem tcp_segment = TcpSegmentFactory::create_tcp_segment_syn_request(
Protocol,
source_address, destination_address,
source_port, destination_port, SequenceNumber );
// Decode the reply segment.
TcpSegmentItem tcp_segment = TcpSegmentFactory::create_tcp_segment( Protocol, is );
- // Filter out only the TCP reset (RST) replies. Note that the sequence
- // number from RST does not match the sent ACK's sequence number.
+ // The TCP SYN ping will receive a RST if the port is closed.
+ // Filter out the TCP reset (RST) replies. Note that the sequence
+ // number from RST does not match the sent SYN's sequence number.
if ( tcp_segment->match_rst_reply( DestinationEndpoint.address() ) )
{
ReceivedReply = true;
TcpSegmentReceiveTimer.cancel(); //lint !e534
}
+ // The TCP SYN ping will receive a SYN/ACK if the port is open.
+ // Filter out the TCP synchronize (SYN/ACK) replies. Note that the sequence
+ // number from SYN/ACK does not match the sent SYN's sequence number.
+ else if ( tcp_segment->match_syn_ack_reply( DestinationEndpoint.address() ) )
+ {
+ ReceivedReply = true;
+
+ tcp_segment->print_syn_ack_reply( TimeSent );
+
+ set_ping_status( PingStatus_SuccessReply );
+
+ TcpSegmentReceiveTimer.cancel(); //lint !e534
+ }
// Unknown TCP reply, start another receive till timeout
else
{
const boost::posix_time::ptime &time_packet_sent
) const = 0;
+ virtual bool match_syn_ack_reply(
+ const boost::asio::ip::address &source_address
+ ) const = 0;
+
+ virtual void print_syn_ack_reply(
+ const boost::posix_time::ptime &time_packet_sent
+ ) const = 0;
+
virtual bool read( std::istream &is ) = 0;
virtual bool write( std::ostream &os ) const = 0;
}
/**
- * @brief Creates a TCP ACK request segment.
+ * @brief Creates a TCP SYN request segment.
*
* @param protocol The segment's network layer protocol, IPv4 or IPv6.
* @param source_address The local address originating the ping.
* @param source_port The local TCP port.
* @param destination_port The remote TCP port.
* @param sequence_number The segment's sequence number to aid in matching RST
- * replies to this ACK request. May be zero.
+ * or SYN/ACK replies to this SYN request. May be zero.
*
- * @return A TCP ACK request segment object.
+ * @return A TCP SYN request segment object.
*/
-TcpSegmentItem TcpSegmentFactory::create_tcp_segment_ack_request(
+TcpSegmentItem TcpSegmentFactory::create_tcp_segment_syn_request(
const tcp_raw_protocol::socket::protocol_type &protocol,
const address &source_address,
const address &destination_address,
if ( tcp_raw_protocol::v4() == protocol )
{
- tcp_segment = create_tcp_ipv4_segment_ack_request(
+ tcp_segment = create_tcp_ipv4_segment_syn_request(
source_address, destination_address,
source_port, destination_port, sequence_number );
}
else if ( tcp_raw_protocol::v6() == protocol )
{
- tcp_segment = create_tcp_ipv6_segment_ack_request(
+ tcp_segment = create_tcp_ipv6_segment_syn_request(
source_address, destination_address,
source_port, destination_port, sequence_number );
}
}
/**
- * @brief Creates a TCP ACK request segment over IPv4.
+ * @brief Creates a TCP SYN request segment over IPv4.
*
* @param source_address The local address originating the ping.
* @param destination_address The remote address where to ping.
* @param source_port The local TCP port.
* @param destination_port The remote TCP port.
* @param sequence_number The segment's sequence number to aid in matching RST
- * replies to this ACK request. May be zero.
+ * or SYN/ACK replies to this SYN request. May be zero.
*
- * @return A TCP ACK request segment object.
+ * @return A TCP SYN request segment object.
*/
-TcpSegmentItem TcpSegmentFactory::create_tcp_ipv4_segment_ack_request(
+TcpSegmentItem TcpSegmentFactory::create_tcp_ipv4_segment_syn_request(
const address &source_address,
const address &destination_address,
const uint16_t source_port,
const uint8_t header_size_in_words = 5; // size in units of 32 bits
const uint16_t window_size_in_octets = 32768;
- // Create a TCP header for an ACK request.
+ // Create a TCP header for a SYN request.
TcpHeader tcp_header;
tcp_header.set_source_port( source_port ); // assign a random ephemeral port number
tcp_header.set_destination_port( destination_port );
tcp_header.set_sequence_number( sequence_number );
tcp_header.set_header_length( header_size_in_words );
- tcp_header.set_acknowledgment( true );
+ tcp_header.set_synchronize( true );
tcp_header.set_window_size( window_size_in_octets ); // window size
// Calculate the checksum of the TCP header
}
/**
- * @brief Creates a TCP ACK request segment over IPv6.
+ * @brief Creates a TCP SYN request segment over IPv6.
*
* @param source_address The local address originating the ping.
* @param destination_address The remote address where to ping.
* @param source_port The local TCP port.
* @param destination_port The remote TCP port.
* @param sequence_number The segment's sequence number to aid in matching RST
- * replies to this ACK request. May be zero.
+ * or SYN/ACK replies to this SYN request. May be zero.
*
- * @return A TCP ACK request segment object.
+ * @return A TCP SYN request segment object.
*/
-TcpSegmentItem TcpSegmentFactory::create_tcp_ipv6_segment_ack_request(
+TcpSegmentItem TcpSegmentFactory::create_tcp_ipv6_segment_syn_request(
const address &source_address,
const address &destination_address,
const uint16_t source_port,
const uint8_t header_size_in_words = 5; // size in units of 32 bits
const uint16_t window_size_in_octets = 32768;
- // Create a TCP header for an ACK request.
+ // Create a TCP header for a SYN request.
TcpHeader tcp_header;
tcp_header.set_source_port( source_port ); // assign a random ephemeral port number
tcp_header.set_destination_port( destination_port );
tcp_header.set_sequence_number( sequence_number );
tcp_header.set_header_length( header_size_in_words );
- tcp_header.set_acknowledgment( true );
+ tcp_header.set_synchronize( true );
tcp_header.set_window_size( window_size_in_octets ); // window size
// Calculate the checksum
const boost::asio::ip::tcp_raw_protocol::socket::protocol_type &protocol,
std::istream &is
);
- static TcpSegmentItem create_tcp_segment_ack_request(
+ static TcpSegmentItem create_tcp_segment_syn_request(
const boost::asio::ip::tcp_raw_protocol::socket::protocol_type &protocol,
const boost::asio::ip::address &source_address,
const boost::asio::ip::address &destination_address,
);
private:
- static TcpSegmentItem create_tcp_ipv4_segment_ack_request(
+ static TcpSegmentItem create_tcp_ipv4_segment_syn_request(
const boost::asio::ip::address &source_address,
const boost::asio::ip::address &destination_address,
const uint16_t source_port,
const uint16_t destination_port,
const uint16_t sequence_number
);
- static TcpSegmentItem create_tcp_ipv6_segment_ack_request(
+ static TcpSegmentItem create_tcp_ipv6_segment_syn_request(
const boost::asio::ip::address &source_address,
const boost::asio::ip::address &destination_address,
const uint16_t source_port,