From 74cca6a4837f91129ce95dcf0c671d16f312d49e Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Sun, 14 Sep 2014 14:13:25 -0300 Subject: [PATCH] Improved documentation on several classes. --- include/packet_sender.h | 95 +++++++++++++++++++++++++++++++++++------ include/packet_writer.h | 7 ++- include/pdu.h | 54 ++++++++++++++++++++--- include/pdu_cacher.h | 28 +++++++++--- include/sniffer.h | 9 ++-- include/tcp.h | 75 ++++++++++++++++++++++++-------- include/udp.h | 23 ++++++++-- 7 files changed, 241 insertions(+), 50 deletions(-) diff --git a/include/packet_sender.h b/include/packet_sender.h index 037daa5..8654346 100644 --- a/include/packet_sender.h +++ b/include/packet_sender.h @@ -47,10 +47,61 @@ namespace Tins { class PDU; /** - * \brief Class that enables sending the created PDUs + * \class PacketSender + * \brief Sends packets through a network interface. * - * PacketSender class is responsible for sending the packets using the - * correct PDU layer. It is responsible for opening the raw sockets. + * This class allows sending packets through a network interface. + * It can send basically two types of packets: + * + * - Those that contain a link layer PDU (EthernetII, SLL, etc). These + * will be serialized and sent through an interface that has to be + * specified. This can be done by providing it when you call + * PacketSender::send, or set a default one using + * PacketSender::default_interface. + * - Those that don't contain a link layer PDU. In this case, the + * kernel will be responsible for picking the appropriate network interface + * based on the destination address. + * + * Sending packets can be done via PacketSender::send: + * + * \code + * // Construct a packet which uses an EthernetII link layer. + * EthernetII pkt1 = ...; + * + * // Construct a packet sender, which we'll use to send packets. + * PacketSender sender; + * + * // Send it through interface eth0 + * sender.send(pkt1, "eth0"); + * + * // Set the default interface to eth0 + * sender.default_interface("eth0"); + * + * // This is now equivalent to the previous send. + * sender.send(pkt1); + * + * // Construct a packet which has no link layer protocol. + * IP ip = IP("192.168.0.1") / TCP(22, 928); + * + * // Here the kernel will figure out which interface to use and it will + * // append the appropriate link layer protocol PDU. It will also perform + * // the necessary ARP lookups in order to use the destination host's + * // hardware address. + * // + * // libtins will find which is the appropriate source IP address to use. + * // This will be done by the kernel as well, but it's required when + * // calculating checksums. + * sender.send(ip); + * \endcode + * + * PacketSender also supports sending a packet and waiting for a response. + * This can be done by using PacketSender::send_recv. + * + * This class opens sockets as it needs to, and closes them when the object + * is destructed. + * + * \sa PacketSender::send + * \sa PacketSender::send_recv */ class PacketSender { public: @@ -209,9 +260,19 @@ namespace Tins { * \brief Sends a PDU and waits for its response. * * This method is used to send PDUs and receive their response. - * It opens the required socket(if it's not open yet). This can be used - * to expect responses for ICMP, ARP, and such packets that are normally - * answered by the host that receives the packet. + * The packet is sent, and then a response is awaited. + * PDU::matches_pdu is called on the packet sent in order to + * check whether a packet received is a response. + * + * This will match every response to a packet. For example, + * if you send a TCP packet, any response matching the same + * IP addresses and ports will be taken as a response to it. + * This also happens for other protocols, such as ARP, ICMP, + * DHCP, DNS, IP, etc. + * + * If you send a packet and get an ICMP response indicating + * an error (such as host unreachable, ttl exceeded, etc), + * that packet will be considered a response. * * \param pdu The PDU to send. * \return Returns the response PDU, 0 if not response was received. @@ -220,12 +281,11 @@ namespace Tins { /** * \brief Sends a PDU and waits for its response. + * + * Sends a packet and receives a response. This overload takes + * a NetworkInterface. * - * This method is used to send PDUs and receive their response. - * It opens the required socket(if it's not open yet). This can be used - * to expect responses for ICMP, ARP, and such packets that are normally - * answered by the host that receives the packet. - * + * \sa PacketSender::send_recv(PDU&); * \param pdu The PDU to send. * \param iface The network interface in which to send and receive. * \return Returns the response PDU, 0 if not response was received. @@ -235,9 +295,12 @@ namespace Tins { #ifndef WIN32 /** * \brief Receives a layer 2 PDU response to a previously sent PDU. + * + * This method is used internally. You should just use PacketSender::send_recv. * - * This PacketSender will receive data from a raw socket, open using the corresponding flag, - * according to the given type of protocol, until a match for the given PDU is received. + * This PacketSender will receive data from a raw socket, open using + * the corresponding flag, according to the given type of protocol, until + * a match for the given PDU is received. * * \param pdu The PDU which will try to match the responses. * \param link_addr The sockaddr struct which will be used to receive the PDU. @@ -249,6 +312,8 @@ namespace Tins { /** * \brief Sends a level 2 PDU. + * + * This method is used internally. You should just use PacketSender::send. * * This method sends a layer 2 PDU, using a raw socket, open * using the corresponding flag, according to the given type of @@ -266,6 +331,8 @@ namespace Tins { /** * \brief Receives a layer 3 PDU response to a previously sent PDU. + * + * This method is used internally. You should just use PacketSender::send_recv. * * This PacketSender will receive data from a raw socket, open using the corresponding flag, * according to the given type of protocol, until a match for the given PDU is received. @@ -280,6 +347,8 @@ namespace Tins { /** * \brief Sends a level 3 PDU. + * + * This method is used internally. You should just use PacketSender::send. * * This method sends a layer 3 PDU, using a raw socket, open using the corresponding flag, * according to the given type of protocol. diff --git a/include/packet_writer.h b/include/packet_writer.h index cf8bc16..43e986b 100644 --- a/include/packet_writer.h +++ b/include/packet_writer.h @@ -119,7 +119,8 @@ public: /** * \brief Constructs a PacketWriter. * - * \deprecated Use the other constructor, which takes a DataLinkType. + * \deprecated Use the PacketWriter(const std::string&, const DataLinkType&) + * constructor. * * \param file_name The file in which to store the written PDUs. * \param lt The link type which will be written to this file. @@ -158,7 +159,9 @@ public: #endif /** - * Destructor. + * \brief Destructor. + * + * Gracefully closes the output file. */ ~PacketWriter(); diff --git a/include/pdu.h b/include/pdu.h index 70dac4b..9934125 100644 --- a/include/pdu.h +++ b/include/pdu.h @@ -53,12 +53,56 @@ namespace Tins { * \class PDU * \brief Base class for protocol data units. * - * Every PDU implementation must inherit this class. PDUs can be serialized, - * therefore allowing a PacketSender to send them through the corresponding - * sockets. + * Every PDU implementation inherits from this class. + * + * PDUs can contain 0 or 1 inner PDU. By stacking several PDUs together, + * you can construct packets. These are created upwards: upper layers + * will be children of the lower ones. + * + * If you want to find a specific protocol within a PDU chain, you can use + * PDU::find_pdu and PDU::rfind_pdu. Both of them take a template parameter + * that indicates the PDU type you are looking for. The first one returns a + * pointer to the first object of that type, and the second one returns a + * reference (and throws if it is not found). * - * PDUs are created upwards: upper layers will be children of the - * lower ones. + * For example: + * + * \code + * // Take a whole packet from somewhere. + * EthernetII packet = ...; + * + * // Find the IP layer + * const IP* ip = packet.find_pdu(); + * if(ip) { + * // If the pointer is not null, then it will point to the IP layer + * } + * + * // Find the TCP layer. This will throw a pdu_not_found exception + * // if there is no TCP layer in this packet. + * const TCP& tcp = packet.rfind_pdu(); + * \endcode + * + * PDU objects can be serialized. Serialization converts the entire PDU + * stack into a vector of bytes. This process might modify some parameters + * on packets depending on which protocols are used in it. For example: + * + * - If the lowest protocol layer is IP (this means that there is no + * link layer protocol in the packet), then it calculates the source address + * that should be used in that IP PDU. \sa IP + * - If a protocol contains a checksum field, its value will be calculated + * and included in its serialized contents. + * - If a protocol contains a "next protocol" field, it is also set based + * on the type of the next PDU in the packet. + * + * If you want to serialize a packet, just use PDU::serialize: + * + * \code + * // Construct a packet + * EthernetII packet = EthernetII() / IP() / TCP() / RawPDU("hello"); + * + * // Now serialize it. This is a std::vector. + * PDU::serialization_type buffer = packet.serialize(); + * \endcode */ class PDU { public: diff --git a/include/pdu_cacher.h b/include/pdu_cacher.h index 77e668d..c71991a 100644 --- a/include/pdu_cacher.h +++ b/include/pdu_cacher.h @@ -78,7 +78,9 @@ public: cached_size() {} /** - * Forwards the call to the cached PDU. \sa PDU::header_size. + * Forwards the call to the cached PDU. + * + * \sa PDU::header_size. */ uint32_t header_size() const { if(cached_serialization.empty()) @@ -87,42 +89,54 @@ public: } /** - * Forwards the call to the cached PDU. \sa PDU::clone. + * Forwards the call to the cached PDU. + * + * \sa PDU::clone. */ PDUCacher *clone() const { return new PDUCacher(*this); } /** - * Forwards the call to the cached PDU. \sa PDU::send. + * Forwards the call to the cached PDU. + * + * \sa PDU::send. */ void send(PacketSender &sender, const NetworkInterface &iface) { cached.send(sender, iface); } /** - * Forwards the call to the cached PDU. \sa PDU::recv_responde. + * Forwards the call to the cached PDU. + * + * \sa PDU::recv_responde. */ PDU *recv_response(PacketSender &sender, const NetworkInterface &iface) { return cached.recv_response(sender, iface); } /** - * Forwards the call to the cached PDU. \sa PDU::matches_response. + * Forwards the call to the cached PDU. + * + * \sa PDU::matches_response. */ bool matches_response(const uint8_t *ptr, uint32_t total_sz) const { return cached.matches_response(ptr, total_sz); } /** - * Forwards the call to the cached PDU. \sa PDU::matches_flag. + * Forwards the call to the cached PDU. + * + * \sa PDU::matches_flag. */ bool matches_flag(PDUType flag) const { return cached.matches_flag(flag); } /** - * Forwards the call to the cached PDU. \sa PDU::pdu_type. + * Forwards the call to the cached PDU. + * + * \sa PDU::pdu_type. */ PDUType pdu_type() const { return cached.pdu_type(); diff --git a/include/sniffer.h b/include/sniffer.h index 19485d5..58e9340 100644 --- a/include/sniffer.h +++ b/include/sniffer.h @@ -265,7 +265,8 @@ namespace Tins { class Sniffer : public BaseSniffer { public: /** - * \deprecated + * \deprecated This enum is no longer necessary. You should use the + * Sniffer(const std::string&, const SnifferConfiguration&) constructor. */ enum promisc_type { NON_PROMISC, @@ -293,7 +294,8 @@ namespace Tins { * By default the interface won't be put into promiscuous mode, and won't * be put into monitor mode. * - * \deprecated Use the constructor that takes a SnifferConfiguration. + * \deprecated Use the Sniffer(const std::string&, const SnifferConfiguration&) + * constructor. * \param device The device which will be sniffed. * \param max_packet_size The maximum packet size to be read. * \param promisc bool indicating wether to put the interface in promiscuous mode.(optional) @@ -309,7 +311,8 @@ namespace Tins { * The maximum capture size is set to 65535. By default the interface won't * be put into promiscuous mode, and won't be put into monitor mode. * - * \deprecated Use the constructor that takes a SnifferConfiguration. + * \deprecated Use the Sniffer(const std::string&, const SnifferConfiguration&) + * constructor. * \param device The device which will be sniffed. * \param promisc Indicates if the interface should be put in promiscuous mode. * \param filter A capture filter to be used on the sniffing session.(optional); diff --git a/include/tcp.h b/include/tcp.h index eb63596..c60f87a 100644 --- a/include/tcp.h +++ b/include/tcp.h @@ -46,10 +46,30 @@ namespace Tins { /** * \class TCP - * \brief Class that represents an TCP PDU. + * \brief Represents a TCP PDU. * - * TCP is the representation of the TCP PDU. Instances of this class - * must be sent over a level 3 PDU, this will otherwise fail. + * This class represents a TCP PDU. + * + * When sending TCP PDUs, the checksum is calculated automatically + * every time you send the packet. + * + * While sniffing, the payload sent in each packet will be wrapped + * in a RawPDU, which is set as the TCP object's inner_pdu. Therefore, + * if you are sniffing and want to see the TCP packet's payload, + * you need to do the following: + * + * \code + * // Get a packet from somewhere. + * TCP tcp = ...; + * + * // Extract the RawPDU object. + * const RawPDU& raw = tcp.rfind_pdu(); + * + * // Finally, take the payload (this is a vector) + * const RawPDU::payload_type& payload = raw.payload(); + * \endcode + * + * \sa RawPDU */ class TCP : public PDU { @@ -78,7 +98,7 @@ namespace Tins { /** * \brief TCP options enum. * - * This enum identifies valid options supported by TCP PDU. + * This enum defines option types supported by TCP PDU. */ enum OptionTypes { EOL = 0, @@ -120,6 +140,7 @@ namespace Tins { * * Creates an instance of TCP. Destination and source port can * be provided, otherwise both will be 0. + * * \param dport Destination port. * \param sport Source port. * */ @@ -129,7 +150,7 @@ namespace Tins { * \brief Constructs TCP object from a buffer. * * If there is not enough size for a TCP header, or any of the - * TLV options are malformed a malformed_packet exception is + * TLV options are malformed, a malformed_packet exception is * thrown. * * Any extra data will be stored in a RawPDU. @@ -142,56 +163,56 @@ namespace Tins { /** * \brief Getter for the destination port field. * - * \return The destination port in an uint16_t. + * \return The destination port field value. */ uint16_t dport() const { return Endian::be_to_host(_tcp.dport); } /** * \brief Getter for the source port field. * - * \return The source port in an uint16_t. + * \return The source port field value. */ uint16_t sport() const { return Endian::be_to_host(_tcp.sport); } /** * \brief Getter for the sequence number field. * - * \return The sequence number in an uint32_t. + * \return The sequence number field value. */ uint32_t seq() const { return Endian::be_to_host(_tcp.seq); } /** * \brief Getter for the acknowledge number field. * - * \return The acknowledge number in an uint32_t. + * \return The acknowledge number field value. */ uint32_t ack_seq() const { return Endian::be_to_host(_tcp.ack_seq); } /** * \brief Getter for the window size field. * - * \return The window size in an uint32_t. + * \return The window size field value. */ uint16_t window() const { return Endian::be_to_host(_tcp.window); } /** * \brief Getter for the checksum field. * - * \return The checksum field in an uint16_t. + * \return The checksum field value. */ uint16_t checksum() const { return Endian::be_to_host(_tcp.check); } /** * \brief Getter for the urgent pointer field. * - * \return The urgent pointer in an uint16_t. + * \return The urgent pointer field value. */ uint16_t urg_ptr() const { return Endian::be_to_host(_tcp.urg_ptr); } /** * \brief Getter for the data offset field. * - * \return Data offset in an uint8_t. + * \return The data offset field value. */ small_uint<4> data_offset() const { return this->_tcp.doff; } @@ -204,7 +225,24 @@ namespace Tins { /** * \brief Gets the value of a flag. + * + * This method gets the value of a specific flag. If you + * want to check for multiple flags at the same time, + * use TCP::flags. + * + * If you want to check if this PDU has the SYN flag on, + * you can do it like this: + * + * \code + * // Get a TCP packet from somewhere. + * TCP tcp = ...; + * + * if(tcp.get_flag(TCP::SYN)) { + * // The SYN flag is on! + * } + * \endcode * + * \sa TCP::flags * \param tcp_flag The polled flag. * \return The value of the flag. */ @@ -220,8 +258,9 @@ namespace Tins { * * \code * TCP tcp = ...; - * if(tcp.flags() == (TCP::SYN | TCP::ACK)) + * if(tcp.flags() == (TCP::SYN | TCP::ACK)) { * // It's a SYN+ACK! + * } * \endcode * * \return The value of the flags field. @@ -379,11 +418,13 @@ namespace Tins { * same time. * * \code + * // Get a TCP packet from somewhere and set the flags to SYN && ACK * TCP tcp = ...; * tcp.flags(TCP::SYN | TCP::ACK); - * // ... - * // only set the ACK, keeping the rest of the old flags. - * tcp.flags(tcp.flags() | TCP::ACK); + * + * // Now also set the PSH flag, without modifying + * // the rest of the flags. + * tcp.flags(tcp.flags() | TCP::PSH); * \endcode * * \param value The new value of the flags. diff --git a/include/udp.h b/include/udp.h index 63150fe..7ce46b8 100644 --- a/include/udp.h +++ b/include/udp.h @@ -38,10 +38,27 @@ namespace Tins { /** * \class UDP - * \brief Class that represents an UDP PDU. + * \brief Represents an UDP PDU. * - * UDP is the representation of the UDP PDU. Instances of this class - * must be sent over a level 3 PDU, this will otherwise fail. + * This class represents an UDP PDU. + * + * While sniffing, the payload sent in each packet will be wrapped + * in a RawPDU, which is set as the UDP object's inner_pdu. Therefore, + * if you are sniffing and want to see the UDP packet's payload, + * you need to do the following: + * + * \code + * // Get a packet from somewhere. + * UDP udp = ...; + * + * // Extract the RawPDU object. + * const RawPDU& raw = udp.rfind_pdu(); + * + * // Finally, take the payload (this is a vector) + * const RawPDU::payload_type& payload = raw.payload(); + * \endcode + * + * \sa RawPDU */ class UDP : public PDU { public: