pkt4.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. // Copyright (C) 2011-2014 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #ifndef PKT4_H
  15. #define PKT4_H
  16. #include <asiolink/io_address.h>
  17. #include <dhcp/option.h>
  18. #include <util/buffer.h>
  19. #include <dhcp/option.h>
  20. #include <dhcp/classify.h>
  21. #include <dhcp/pkt.h>
  22. #include <boost/shared_ptr.hpp>
  23. #include <iostream>
  24. #include <vector>
  25. #include <set>
  26. #include <time.h>
  27. namespace isc {
  28. namespace dhcp {
  29. /// @brief Represents DHCPv4 packet
  30. ///
  31. /// This class represents a single DHCPv4 packet. It handles both incoming
  32. /// and transmitted packets, parsing incoming options, options handling
  33. /// (add, get, remove), on-wire assembly, sanity checks and other operations.
  34. /// This specific class has several DHCPv4-specific methods, but it uses a lot
  35. /// of common operations from its base @c Pkt class that is shared with Pkt6.
  36. class Pkt4 : public Pkt {
  37. public:
  38. /// length of the CHADDR field in DHCPv4 message
  39. const static size_t MAX_CHADDR_LEN = 16;
  40. /// length of the SNAME field in DHCPv4 message
  41. const static size_t MAX_SNAME_LEN = 64;
  42. /// length of the FILE field in DHCPv4 message
  43. const static size_t MAX_FILE_LEN = 128;
  44. /// specifies DHCPv4 packet header length (fixed part)
  45. const static size_t DHCPV4_PKT_HDR_LEN = 236;
  46. /// Mask for the value of flags field in the DHCPv4 message
  47. /// to check whether client requested broadcast response.
  48. const static uint16_t FLAG_BROADCAST_MASK = 0x8000;
  49. /// Constructor, used in replying to a message.
  50. ///
  51. /// @param msg_type type of message (e.g. DHCPDISOVER=1)
  52. /// @param transid transaction-id
  53. Pkt4(uint8_t msg_type, uint32_t transid);
  54. /// @brief Constructor, used in message reception.
  55. ///
  56. /// Creates new message. Pkt4 will copy data to bufferIn_
  57. /// buffer on creation.
  58. ///
  59. /// @param data pointer to received data
  60. /// @param len size of buffer to be allocated for this packet.
  61. Pkt4(const uint8_t* data, size_t len);
  62. /// @brief Prepares on-wire format of DHCPv4 packet.
  63. ///
  64. /// Prepares on-wire format of message and all its options.
  65. /// Options must be stored in options_ field.
  66. /// Output buffer will be stored in buffer_out_.
  67. /// The buffer_out_ is cleared before writting to the buffer.
  68. ///
  69. /// @throw InvalidOperation if packing fails
  70. virtual void pack();
  71. /// @brief Parses on-wire form of DHCPv4 packet.
  72. ///
  73. /// Parses received packet, stored in on-wire format in bufferIn_.
  74. ///
  75. /// Will create a collection of option objects that will
  76. /// be stored in options_ container.
  77. ///
  78. /// Method with throw exception if packet parsing fails.
  79. virtual void unpack();
  80. /// @brief performs sanity check on a packet.
  81. ///
  82. /// This is usually performed after unpack(). It checks if packet is sane:
  83. /// required options are present, fields have sane content etc.
  84. /// For example verifies that DHCP_MESSAGE_TYPE is present and have
  85. /// reasonable value. This method is expected to grow significantly.
  86. /// It makes sense to separate unpack() and check() for testing purposes.
  87. ///
  88. /// @todo It is called from unpack() directly. It should be separated.
  89. ///
  90. /// Method will throw exception if anomaly is found.
  91. void check();
  92. /// @brief Returns text representation of the packet.
  93. ///
  94. /// This function is useful mainly for debugging.
  95. ///
  96. /// @return string with text representation
  97. std::string toText();
  98. /// @brief Returns the size of the required buffer to build the packet.
  99. ///
  100. /// Returns the size of the required buffer to build the packet with
  101. /// the current set of packet options.
  102. ///
  103. /// @return number of bytes required to build this packet
  104. size_t len();
  105. /// @brief Sets hops field.
  106. ///
  107. /// @param hops value to be set
  108. void setHops(uint8_t hops) { hops_ = hops; };
  109. /// @brief Returns hops field.
  110. ///
  111. /// @return hops field
  112. uint8_t getHops() const { return (hops_); };
  113. // Note: There's no need to manipulate OP field directly,
  114. // thus no setOp() method. See op_ comment.
  115. /// @brief Returns op field.
  116. ///
  117. /// @return op field
  118. uint8_t getOp() const { return (op_); };
  119. /// @brief Sets secs field.
  120. ///
  121. /// @param secs value to be set
  122. void setSecs(uint16_t secs) { secs_ = secs; };
  123. /// @brief Returns secs field.
  124. ///
  125. /// @return secs field
  126. uint16_t getSecs() const { return (secs_); };
  127. /// @brief Sets flags field.
  128. ///
  129. /// @param flags value to be set
  130. void setFlags(uint16_t flags) { flags_ = flags; };
  131. /// @brief Returns flags field.
  132. ///
  133. /// @return flags field
  134. uint16_t getFlags() const { return (flags_); };
  135. /// @brief Returns ciaddr field.
  136. ///
  137. /// @return ciaddr field
  138. const isc::asiolink::IOAddress&
  139. getCiaddr() const { return (ciaddr_); };
  140. /// @brief Sets ciaddr field.
  141. ///
  142. /// @param ciaddr value to be set
  143. void
  144. setCiaddr(const isc::asiolink::IOAddress& ciaddr) { ciaddr_ = ciaddr; };
  145. /// @brief Returns siaddr field.
  146. ///
  147. /// @return siaddr field
  148. const isc::asiolink::IOAddress&
  149. getSiaddr() const { return (siaddr_); };
  150. /// @brief Sets siaddr field.
  151. ///
  152. /// @param siaddr value to be set
  153. void
  154. setSiaddr(const isc::asiolink::IOAddress& siaddr) { siaddr_ = siaddr; };
  155. /// @brief Returns yiaddr field.
  156. ///
  157. /// @return yiaddr field
  158. const isc::asiolink::IOAddress&
  159. getYiaddr() const { return (yiaddr_); };
  160. /// @brief Sets yiaddr field.
  161. ///
  162. /// @param yiaddr value to be set
  163. void
  164. setYiaddr(const isc::asiolink::IOAddress& yiaddr) { yiaddr_ = yiaddr; };
  165. /// @brief Returns giaddr field.
  166. ///
  167. /// @return giaddr field
  168. const isc::asiolink::IOAddress&
  169. getGiaddr() const { return (giaddr_); };
  170. /// @brief Sets giaddr field.
  171. ///
  172. /// @param giaddr value to be set
  173. void
  174. setGiaddr(const isc::asiolink::IOAddress& giaddr) { giaddr_ = giaddr; };
  175. /// @brief Returns DHCP message type (e.g. 1 = DHCPDISCOVER).
  176. ///
  177. /// @return message type
  178. uint8_t getType() const;
  179. /// @brief Sets DHCP message type (e.g. 1 = DHCPDISCOVER).
  180. ///
  181. /// @param type message type to be set
  182. void setType(uint8_t type);
  183. /// @brief Returns sname field
  184. ///
  185. /// Note: This is 64 bytes long field. It doesn't have to be
  186. /// null-terminated. Do not use strlen() or similar on it.
  187. ///
  188. /// @return sname field
  189. const OptionBuffer
  190. getSname() const { return (std::vector<uint8_t>(sname_, &sname_[MAX_SNAME_LEN])); };
  191. /// @brief Sets sname field.
  192. ///
  193. /// @param sname value to be set
  194. /// @param sname_len length of the sname buffer (up to MAX_SNAME_LEN)
  195. void setSname(const uint8_t* sname, size_t sname_len = MAX_SNAME_LEN);
  196. /// @brief Returns file field
  197. ///
  198. /// Note: This is 128 bytes long field. It doesn't have to be
  199. /// null-terminated. Do not use strlen() or similar on it.
  200. ///
  201. /// @return pointer to file field
  202. const OptionBuffer
  203. getFile() const { return (std::vector<uint8_t>(file_, &file_[MAX_FILE_LEN])); };
  204. /// Sets file field
  205. ///
  206. /// @param file value to be set
  207. /// @param file_len length of the file buffer (up to MAX_FILE_LEN)
  208. void
  209. setFile(const uint8_t* file, size_t file_len = MAX_FILE_LEN);
  210. /// @brief Sets hardware address.
  211. ///
  212. /// Sets parameters of hardware address. hlen specifies
  213. /// length of mac_addr buffer. Content of mac_addr buffer
  214. /// will be copied to appropriate field.
  215. ///
  216. /// Note: mac_addr must be a buffer of at least hlen bytes.
  217. ///
  218. /// @param htype hardware type (will be sent in htype field)
  219. /// @param hlen hardware length (will be sent in hlen field)
  220. /// @param mac_addr pointer to hardware address
  221. void setHWAddr(uint8_t htype, uint8_t hlen,
  222. const std::vector<uint8_t>& mac_addr);
  223. /// @brief Sets hardware address
  224. ///
  225. /// Sets hardware address, based on existing HWAddr structure
  226. /// @param addr already filled in HWAddr structure
  227. /// @throw BadValue if addr is null
  228. void setHWAddr(const HWAddrPtr& addr);
  229. /// Returns htype field
  230. ///
  231. /// @return hardware type
  232. uint8_t
  233. getHtype() const;
  234. /// Returns hlen field
  235. ///
  236. /// @return hardware address length
  237. uint8_t
  238. getHlen() const;
  239. /// @brief returns hardware address information
  240. /// @return hardware address structure
  241. HWAddrPtr getHWAddr() const { return (hwaddr_); }
  242. /// @brief Add an option.
  243. ///
  244. /// @throw BadValue if option with that type is already present.
  245. ///
  246. /// @param opt option to be added
  247. virtual void
  248. addOption(const OptionPtr& opt);
  249. /// @brief Sets local HW address.
  250. ///
  251. /// Sets the source HW address for the outgoing packet or
  252. /// destination HW address for the incoming packet.
  253. ///
  254. /// @note mac_addr must be a buffer of at least hlen bytes.
  255. ///
  256. /// @param htype hardware type (will be sent in htype field)
  257. /// @param hlen hardware length (will be sent in hlen field)
  258. /// @param mac_addr pointer to hardware address
  259. void setLocalHWAddr(const uint8_t htype, const uint8_t hlen,
  260. const std::vector<uint8_t>& mac_addr);
  261. /// @brief Sets local HW address.
  262. ///
  263. /// Sets hardware address from an existing HWAddr structure.
  264. /// The local address is a source address for outgoing
  265. /// packet and destination address for incoming packet.
  266. ///
  267. /// @param addr structure representing HW address.
  268. ///
  269. /// @throw BadValue if addr is null
  270. void setLocalHWAddr(const HWAddrPtr& addr);
  271. /// @brief Returns local HW address.
  272. ///
  273. /// @return local HW addr.
  274. HWAddrPtr getLocalHWAddr() const {
  275. return (local_hwaddr_);
  276. }
  277. /// @brief Checks if a DHCPv4 message has been relayed.
  278. ///
  279. /// This function returns a boolean value which indicates whether a DHCPv4
  280. /// message has been relayed (if true is returned) or not (if false).
  281. ///
  282. /// This function uses a combination of Giaddr and Hops. It is expected that
  283. /// if Giaddr is not 0, the Hops is greater than 0. In this case the message
  284. /// is considered relayed. If Giaddr is 0, the Hops value must also be 0. In
  285. /// this case the message is considered non-relayed. For any other
  286. /// combination of Giaddr and Hops, an exception is thrown to indicate that
  287. /// the message is malformed.
  288. ///
  289. /// @return Boolean value which indicates whether the message is relayed
  290. /// (true) or non-relayed (false).
  291. /// @throw isc::BadValue if invalid combination of Giaddr and Hops values is
  292. /// found.
  293. bool isRelayed() const;
  294. /// @brief That's the data of input buffer used in RX packet.
  295. ///
  296. /// @note Note that InputBuffer does not store the data itself, but just
  297. /// expects that data will be valid for the whole life of InputBuffer.
  298. /// Therefore we need to keep the data around.
  299. ///
  300. /// @warning This public member is accessed by derived
  301. /// classes directly. One of such derived classes is
  302. /// @ref perfdhcp::PerfPkt4. The impact on derived clasess'
  303. /// behavior must be taken into consideration before making
  304. /// changes to this member such as access scope restriction or
  305. /// data format change etc. This field is also public, because
  306. /// it may be modified by callouts (which are written in C++ now,
  307. /// but we expect to also have them in Python, so any accesibility
  308. /// methods would overly complicate things here and degrade
  309. /// performance).
  310. std::vector<uint8_t> data_;
  311. private:
  312. /// @brief Generic method that validates and sets HW address.
  313. ///
  314. /// This is a generic method used by all modifiers of this class
  315. /// which set class members representing HW address.
  316. ///
  317. /// @param htype hardware type.
  318. /// @param hlen hardware length.
  319. /// @param mac_addr pointer to actual hardware address.
  320. /// @param [out] hw_addr pointer to a class member to be modified.
  321. ///
  322. /// @trow isc::OutOfRange if invalid HW address specified.
  323. virtual void setHWAddrMember(const uint8_t htype, const uint8_t hlen,
  324. const std::vector<uint8_t>& mac_addr,
  325. HWAddrPtr& hw_addr);
  326. protected:
  327. /// converts DHCP message type to BOOTP op type
  328. ///
  329. /// @param dhcpType DHCP message type (e.g. DHCPDISCOVER)
  330. ///
  331. /// @return BOOTP type (BOOTREQUEST or BOOTREPLY)
  332. uint8_t
  333. DHCPTypeToBootpType(uint8_t dhcpType);
  334. /// @brief No-op
  335. ///
  336. /// This method returns hardware address generated from the IPv6 link-local
  337. /// address. As there is no IPv4-equivalent, it always returns NULL.
  338. /// We need this stub implementation here, to keep all the get hardware
  339. /// address logic in the base class.
  340. ///
  341. /// @return always NULL
  342. virtual HWAddrPtr getMACFromSrcLinkLocalAddr() {
  343. return (HWAddrPtr());
  344. }
  345. /// @brief No-op
  346. ///
  347. /// This method returns hardware address extracted from an IPv6 relay agent.
  348. /// option. As there is no IPv4-equivalent, it always returns NULL.
  349. /// We need this stub implementation here, to keep all the get hardware
  350. /// address logic in the base class.
  351. ///
  352. /// @return always NULL
  353. virtual HWAddrPtr getMACFromIPv6RelayOpt() {
  354. return (HWAddrPtr());
  355. }
  356. /// local HW address (dst if receiving packet, src if sending packet)
  357. HWAddrPtr local_hwaddr_;
  358. /// @brief message operation code
  359. ///
  360. /// Note: This is legacy BOOTP field. There's no need to manipulate it
  361. /// directly. Its value is set based on DHCP message type. Note that
  362. /// DHCPv4 protocol reuses BOOTP message format, so this field is
  363. /// kept due to BOOTP format. This is NOT DHCPv4 type (DHCPv4 message
  364. /// type is kept in message type option).
  365. uint8_t op_;
  366. /// @brief link-layer address and hardware information
  367. /// represents 3 fields: htype (hardware type, 1 byte), hlen (length of the
  368. /// hardware address, up to 16) and chaddr (hardware address field,
  369. /// 16 bytes)
  370. HWAddrPtr hwaddr_;
  371. /// Number of relay agents traversed
  372. uint8_t hops_;
  373. /// elapsed (number of seconds since beginning of transmission)
  374. uint16_t secs_;
  375. /// flags
  376. uint16_t flags_;
  377. /// ciaddr field (32 bits): Client's IP address
  378. isc::asiolink::IOAddress ciaddr_;
  379. /// yiaddr field (32 bits): Client's IP address ("your"), set by server
  380. isc::asiolink::IOAddress yiaddr_;
  381. /// siaddr field (32 bits): next server IP address in boot process(e.g.TFTP)
  382. isc::asiolink::IOAddress siaddr_;
  383. /// giaddr field (32 bits): Gateway IP address
  384. isc::asiolink::IOAddress giaddr_;
  385. /// sname field (64 bytes)
  386. uint8_t sname_[MAX_SNAME_LEN];
  387. /// file field (128 bytes)
  388. uint8_t file_[MAX_FILE_LEN];
  389. // end of real DHCPv4 fields
  390. }; // Pkt4 class
  391. /// @brief A pointer to Pkt4 object.
  392. typedef boost::shared_ptr<Pkt4> Pkt4Ptr;
  393. } // isc::dhcp namespace
  394. } // isc namespace
  395. #endif