diff --git a/include/icmp.h b/include/icmp.h index 566a9d1..c4792c0 100644 --- a/include/icmp.h +++ b/include/icmp.h @@ -149,6 +149,14 @@ namespace Tins { /** \brief Returns the ICMP code flag. */ uint8_t code() const { return _icmp.code; } + + /** \brief Returns the echo id. + */ + uint16_t id() const { return _icmp.un.echo.id; } + + /** \brief Returns the echo sequence number. + */ + uint16_t sequence() const { return _icmp.un.echo.sequence; } /** \brief Returns the header size. * diff --git a/include/packetsender.h b/include/packetsender.h index 62de545..a28e560 100644 --- a/include/packetsender.h +++ b/include/packetsender.h @@ -44,6 +44,8 @@ namespace Tins { */ class PacketSender { public: + static const uint32_t DEFAULT_TIMEOUT; + enum SocketType { ETHER_SOCKET, IP_SOCKET, @@ -55,7 +57,7 @@ namespace Tins { /** * \brief Constructor for PacketSender objects. */ - PacketSender(); + PacketSender(uint32_t recv_timeout = DEFAULT_TIMEOUT); /** * \brief @@ -84,9 +86,12 @@ namespace Tins { typedef std::map SocketTypeMap; int find_type(SocketType type); + + PDU *recv_match_loop(int sock, PDU *pdu, struct sockaddr* link_addr, socklen_t addrlen); std::vector _sockets; SocketTypeMap _types; + uint32_t _timeout; }; }; diff --git a/src/packetsender.cpp b/src/packetsender.cpp index b529ec6..bdcd1f9 100644 --- a/src/packetsender.cpp +++ b/src/packetsender.cpp @@ -31,13 +31,15 @@ #include #include #include +#include #include "packetsender.h" #include "utils.h" //borrar const int Tins::PacketSender::INVALID_RAW_SOCKET = -10; +const uint32_t Tins::PacketSender::DEFAULT_TIMEOUT = 2; -Tins::PacketSender::PacketSender() : _sockets(SOCKETS_END, INVALID_RAW_SOCKET) { +Tins::PacketSender::PacketSender(uint32_t recv_timeout) : _sockets(SOCKETS_END, INVALID_RAW_SOCKET), _timeout(recv_timeout) { _types[IP_SOCKET] = IPPROTO_RAW; _types[ICMP_SOCKET] = IPPROTO_ICMP; } @@ -109,38 +111,13 @@ bool Tins::PacketSender::send_l2(PDU *pdu, struct sockaddr* link_addr, uint32_t Tins::PDU *Tins::PacketSender::recv_l2(PDU *pdu, struct sockaddr *link_addr, uint32_t len_link_addr) { if(!open_l2_socket()) return 0; - uint8_t buffer[2048]; - int sock = _sockets[ETHER_SOCKET]; - bool done = false; - socklen_t addrlen = len_link_addr; - - while(!done) { - ssize_t size = recvfrom(sock, buffer, 2048, 0, link_addr, &addrlen); - if(size == -1) - return 0; - if(pdu->matches_response(buffer, size)) { - return pdu->clone_packet(buffer, size); - } - } - return 0; + return recv_match_loop(_sockets[ETHER_SOCKET], pdu, link_addr, len_link_addr); } Tins::PDU *Tins::PacketSender::recv_l3(PDU *pdu, struct sockaddr* link_addr, uint32_t len_link_addr, SocketType type) { if(!open_l3_socket(type)) return 0; - uint8_t buffer[2048]; - int sock = _sockets[type]; - bool done = false; - socklen_t addrlen = len_link_addr; - - while(!done) { - ssize_t size = recvfrom(sock, buffer, 2048, 0, link_addr, &addrlen); - if(size == -1) - return 0; - if(pdu->matches_response(buffer, size)) - return pdu->clone_packet(buffer, size); - } - return 0; + return recv_match_loop(_sockets[type], pdu, link_addr, len_link_addr); } bool Tins::PacketSender::send_l3(PDU *pdu, struct sockaddr* link_addr, uint32_t len_link_addr, SocketType type) { @@ -157,6 +134,32 @@ bool Tins::PacketSender::send_l3(PDU *pdu, struct sockaddr* link_addr, uint32_t return ret_val; } +Tins::PDU *Tins::PacketSender::recv_match_loop(int sock, PDU *pdu, struct sockaddr* link_addr, socklen_t addrlen) { + fd_set readfds; + struct timeval timeout; + int read; + uint8_t buffer[2048]; + time_t end_time = time(0) + _timeout; + timeout.tv_sec = _timeout; + timeout.tv_usec = 0; + while(true) { + FD_ZERO(&readfds); + FD_SET(sock, &readfds); + if((read = select(sock + 1, &readfds, 0, 0, &timeout)) == -1) + return 0; + if(FD_ISSET(sock, &readfds)) { + ssize_t size = recvfrom(sock, buffer, 2048, 0, link_addr, &addrlen); + if(pdu->matches_response(buffer, size)) + return pdu->clone_packet(buffer, size); + } + time_t this_time = time(0); + if(end_time <= this_time) + return 0; + timeout.tv_sec = end_time - this_time; + } + return 0; +} + int Tins::PacketSender::find_type(SocketType type) { SocketTypeMap::iterator it = _types.find(type); if(it == _types.end())