pkt6.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. // Copyright (C) 2011-2013 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 PKT6_H
  15. #define PKT6_H
  16. #include <asiolink/io_address.h>
  17. #include <dhcp/option.h>
  18. #include <boost/date_time/posix_time/posix_time.hpp>
  19. #include <boost/shared_array.hpp>
  20. #include <boost/shared_ptr.hpp>
  21. #include <iostream>
  22. #include <time.h>
  23. namespace isc {
  24. namespace dhcp {
  25. class Pkt6;
  26. typedef boost::shared_ptr<Pkt6> Pkt6Ptr;
  27. class Pkt6 {
  28. public:
  29. /// specifies non-relayed DHCPv6 packet header length (over UDP)
  30. const static size_t DHCPV6_PKT_HDR_LEN = 4;
  31. /// specifies relay DHCPv6 packet header length (over UDP)
  32. const static size_t DHCPV6_RELAY_HDR_LEN = 34;
  33. /// DHCPv6 transport protocol
  34. enum DHCPv6Proto {
  35. UDP = 0, // most packets are UDP
  36. TCP = 1 // there are TCP DHCPv6 packets (bulk leasequery, failover)
  37. };
  38. /// @brief defines relay search pattern
  39. ///
  40. /// Defines order in which options are searched in a message that
  41. /// passed through mulitple relays. RELAY_SEACH_FROM_CLIENT will
  42. /// start search from the relay that was the closest to the client
  43. /// (i.e. innermost in the encapsulated message, which also means
  44. /// this was the first relay that forwarded packet received by the
  45. /// server and this will be the last relay that will handle the
  46. /// response that server sent towards the client.).
  47. /// RELAY_SEARCH_FROM_SERVER is the opposite. This will be the
  48. /// relay closest to the server (i.e. outermost in the encapsulated
  49. /// message, which also means it was the last relay that relayed
  50. /// the received message and will be the first one to process
  51. /// server's response). RELAY_GET_FIRST will try to get option from
  52. /// the first relay only (closest to the client), RELAY_GET_LAST will
  53. /// try to get option form the the last relay (closest to the server).
  54. enum RelaySearchOrder {
  55. RELAY_SEARCH_FROM_CLIENT = 1,
  56. RELAY_SEARCH_FROM_SERVER = 2,
  57. RELAY_GET_FIRST = 3,
  58. RELAY_GET_LAST = 4
  59. };
  60. /// @brief structure that describes a single relay information
  61. ///
  62. /// Client sends messages. Each relay along its way will encapsulate the message.
  63. /// This structure represents all information added by a single relay.
  64. struct RelayInfo {
  65. /// @brief default constructor
  66. RelayInfo();
  67. uint8_t msg_type_; ///< message type (RELAY-FORW oro RELAY-REPL)
  68. uint8_t hop_count_; ///< number of traversed relays (up to 32)
  69. isc::asiolink::IOAddress linkaddr_;///< fixed field in relay-forw/relay-reply
  70. isc::asiolink::IOAddress peeraddr_;///< fixed field in relay-forw/relay-reply
  71. /// @brief length of the relay_msg_len
  72. /// Used when calculating length during pack/unpack
  73. uint16_t relay_msg_len_;
  74. /// options received from a specified relay, except relay-msg option
  75. isc::dhcp::OptionCollection options_;
  76. };
  77. /// Constructor, used in replying to a message
  78. ///
  79. /// @param msg_type type of message (SOLICIT=1, ADVERTISE=2, ...)
  80. /// @param transid transaction-id
  81. /// @param proto protocol (TCP or UDP)
  82. Pkt6(uint8_t msg_type,
  83. uint32_t transid,
  84. DHCPv6Proto proto = UDP);
  85. /// Constructor, used in message transmission
  86. ///
  87. /// Creates new message. Transaction-id will randomized.
  88. ///
  89. /// @param buf pointer to a buffer of received packet content
  90. /// @param len size of buffer of received packet content
  91. /// @param proto protocol (usually UDP, but TCP will be supported eventually)
  92. Pkt6(const uint8_t* buf, uint32_t len, DHCPv6Proto proto = UDP);
  93. /// @brief Prepares on-wire format.
  94. ///
  95. /// Prepares on-wire format of message and all its options.
  96. /// Options must be stored in options_ field.
  97. /// Output buffer will be stored in data_. Length
  98. /// will be set in data_len_.
  99. ///
  100. /// @throw BadValue if packet protocol is invalid, InvalidOperation
  101. /// if packing fails, or NotImplemented if protocol is TCP (IPv6 over TCP is
  102. /// not yet supported).
  103. void pack();
  104. /// @brief Dispatch method that handles binary packet parsing.
  105. ///
  106. /// This method calls appropriate dispatch function (unpackUDP or
  107. /// unpackTCP).
  108. ///
  109. /// @return true if parsing was successful
  110. bool unpack();
  111. /// @brief Returns reference to output buffer.
  112. ///
  113. /// Returned buffer will contain reasonable data only for
  114. /// output (TX) packet and after pack() was called. This buffer
  115. /// is only valid till Pkt6 object is valid.
  116. ///
  117. /// RX packet or TX packet before pack() will return buffer with
  118. /// zero length
  119. ///
  120. /// @return reference to output buffer
  121. const isc::util::OutputBuffer& getBuffer() const { return (bufferOut_); };
  122. /// @brief Returns protocol of this packet (UDP or TCP).
  123. ///
  124. /// @return protocol type
  125. DHCPv6Proto getProto();
  126. /// Sets protocol of this packet.
  127. ///
  128. /// @param proto protocol (UDP or TCP)
  129. void setProto(DHCPv6Proto proto = UDP) { proto_ = proto; }
  130. /// @brief Returns text representation of the packet.
  131. ///
  132. /// This function is useful mainly for debugging.
  133. ///
  134. /// @return string with text representation
  135. std::string toText();
  136. /// @brief Returns length of the packet.
  137. ///
  138. /// This function returns size required to hold this packet.
  139. /// It includes DHCPv6 header and all options stored in
  140. /// options_ field.
  141. ///
  142. /// Note: It does not return proper length of incoming packets
  143. /// before they are unpacked.
  144. ///
  145. /// @return number of bytes required to assemble this packet
  146. uint16_t len();
  147. /// Returns message type (e.g. 1 = SOLICIT)
  148. ///
  149. /// @return message type
  150. uint8_t getType() const { return (msg_type_); }
  151. /// Sets message type (e.g. 1 = SOLICIT)
  152. ///
  153. /// @param type message type to be set
  154. void setType(uint8_t type) { msg_type_=type; };
  155. /// @brief Sets transaction-id value
  156. ///
  157. /// @param transid transaction-id to be set.
  158. void setTransid(uint32_t transid) { transid_ = transid; }
  159. /// Returns value of transaction-id field
  160. ///
  161. /// @return transaction-id
  162. uint32_t getTransid() const { return (transid_); };
  163. /// Adds an option to this packet.
  164. ///
  165. /// @param opt option to be added.
  166. void addOption(const OptionPtr& opt);
  167. /// @brief Returns the first option of specified type.
  168. ///
  169. /// Returns the first option of specified type. Note that in DHCPv6 several
  170. /// instances of the same option are allowed (and frequently used).
  171. /// Also see \ref getOptions().
  172. ///
  173. /// @param type option type we are looking for
  174. ///
  175. /// @return pointer to found option (or NULL)
  176. OptionPtr getOption(uint16_t type);
  177. /// @brief returns option inserted by relay
  178. ///
  179. /// Returns an option from specified relay scope (inserted by a given relay
  180. /// if this is received packet or to be decapsulated by a given relay if
  181. /// this is a transmitted packet). nesting_level specifies which relay
  182. /// scope is to be used. 0 is the outermost encapsulation (relay closest to
  183. /// the server). pkt->relay_info_.size() - 1 is the innermost encapsulation
  184. /// (relay closest to the client).
  185. ///
  186. /// @throw isc::OutOfRange if nesting level has invalid value.
  187. ///
  188. /// @param option_code code of the requested option
  189. /// @param nesting_level see description above
  190. ///
  191. /// @return pointer to the option (or NULL if there is no such option)
  192. OptionPtr getRelayOption(uint16_t option_code, uint8_t nesting_level);
  193. /// @brief Return first instance of a specified option
  194. ///
  195. /// When a client's packet traverses multiple relays, each passing relay may
  196. /// insert extra options. This method allows the specific instance of a given
  197. /// option to be obtained (e.g. closest to the client, closest to the server,
  198. /// etc.) See @ref RelaySearchOrder for a detailed description.
  199. ///
  200. /// @param option_code searched option
  201. /// @param order option search order (see @ref RelaySearchOrder)
  202. /// @return option pointer (or NULL if no option matches specified criteria)
  203. OptionPtr getAnyRelayOption(uint16_t option_code, RelaySearchOrder order);
  204. /// @brief Returns all instances of specified type.
  205. ///
  206. /// Returns all instances of options of the specified type. DHCPv6 protocol
  207. /// allows (and uses frequently) multiple instances.
  208. ///
  209. /// @param type option type we are looking for
  210. /// @return instance of option collection with requested options
  211. isc::dhcp::OptionCollection getOptions(uint16_t type);
  212. /// Attempts to delete first suboption of requested type
  213. ///
  214. /// @param type Type of option to be deleted.
  215. ///
  216. /// @return true if option was deleted, false if no such option existed
  217. bool delOption(uint16_t type);
  218. /// @brief This method copies data from output buffer to input buffer
  219. ///
  220. /// This is useful only in testing
  221. void repack();
  222. /// @brief Sets remote address.
  223. ///
  224. /// @param remote specifies remote address
  225. void setRemoteAddr(const isc::asiolink::IOAddress& remote) { remote_addr_ = remote; }
  226. /// @brief Returns remote address
  227. ///
  228. /// @return remote address
  229. const isc::asiolink::IOAddress& getRemoteAddr() const {
  230. return (remote_addr_);
  231. }
  232. /// @brief Sets local address.
  233. ///
  234. /// @param local specifies local address
  235. void setLocalAddr(const isc::asiolink::IOAddress& local) { local_addr_ = local; }
  236. /// @brief Returns local address.
  237. ///
  238. /// @return local address
  239. const isc::asiolink::IOAddress& getLocalAddr() const {
  240. return (local_addr_);
  241. }
  242. /// @brief Sets local port.
  243. ///
  244. /// @param local specifies local port
  245. void setLocalPort(uint16_t local) { local_port_ = local; }
  246. /// @brief Returns local port.
  247. ///
  248. /// @return local port
  249. uint16_t getLocalPort() const { return (local_port_); }
  250. /// @brief Sets remote port.
  251. ///
  252. /// @param remote specifies remote port
  253. void setRemotePort(uint16_t remote) { remote_port_ = remote; }
  254. /// @brief Returns remote port.
  255. ///
  256. /// @return remote port
  257. uint16_t getRemotePort() const { return (remote_port_); }
  258. /// @brief Sets interface index.
  259. ///
  260. /// @param ifindex specifies interface index.
  261. void setIndex(uint32_t ifindex) { ifindex_ = ifindex; };
  262. /// @brief Returns interface index.
  263. ///
  264. /// @return interface index
  265. uint32_t getIndex() const { return (ifindex_); };
  266. /// @brief Returns interface name.
  267. ///
  268. /// Returns interface name over which packet was received or is
  269. /// going to be transmitted.
  270. ///
  271. /// @return interface name
  272. std::string getIface() const { return iface_; };
  273. /// @brief Returns packet timestamp.
  274. ///
  275. /// Returns packet timestamp value updated when
  276. /// packet is received or sent.
  277. ///
  278. /// @return packet timestamp.
  279. const boost::posix_time::ptime& getTimestamp() const { return timestamp_; }
  280. /// @brief Sets interface name.
  281. ///
  282. /// Sets interface name over which packet was received or is
  283. /// going to be transmitted.
  284. ///
  285. /// @return interface name
  286. void setIface(const std::string& iface ) { iface_ = iface; };
  287. /// @brief add information about one traversed relay
  288. ///
  289. /// This adds information about one traversed relay, i.e.
  290. /// one relay-forw or relay-repl level of encapsulation.
  291. ///
  292. /// @param relay structure with necessary relay information
  293. void addRelayInfo(const RelayInfo& relay);
  294. /// collection of options present in this message
  295. ///
  296. /// @warning This public member is accessed by derived
  297. /// classes directly. One of such derived classes is
  298. /// @ref perfdhcp::PerfPkt6. The impact on derived clasess'
  299. /// behavior must be taken into consideration before making
  300. /// changes to this member such as access scope restriction or
  301. /// data format change etc.
  302. isc::dhcp::OptionCollection options_;
  303. /// @brief Update packet timestamp.
  304. ///
  305. /// Updates packet timestamp. This method is invoked
  306. /// by interface manager just before sending or
  307. /// just after receiving it.
  308. /// @throw isc::Unexpected if timestamp update failed
  309. void updateTimestamp();
  310. /// @brief Return textual type of packet.
  311. ///
  312. /// Returns the name of valid packet received by the server (e.g. SOLICIT).
  313. /// If the packet is unknown - or if it is a valid DHCP packet but not one
  314. /// expected to be received by the server (such as an ADVERTISE), the string
  315. /// "UNKNOWN" is returned. This method is used in debug messages.
  316. ///
  317. /// As the operation of the method does not depend on any server state, it
  318. /// is declared static. There is also non-static getName() method that
  319. /// works on Pkt6 objects.
  320. ///
  321. /// @param type DHCPv6 packet type
  322. ///
  323. /// @return Pointer to "const" string containing the packet name.
  324. /// Note that this string is statically allocated and MUST NOT
  325. /// be freed by the caller.
  326. static const char* getName(uint8_t type);
  327. /// @brief returns textual representation of packet type.
  328. ///
  329. /// This method requires an object. There is also static version, which
  330. /// requires one parameter (type).
  331. ///
  332. /// @return Pointer to "const" string containing packet name.
  333. /// Note that this string is statically allocated and MUST NOT
  334. /// be freed by the caller.
  335. const char* getName() const;
  336. /// @brief Set callback function to be used to parse options.
  337. ///
  338. /// @param callback An instance of the callback function or NULL to
  339. /// uninstall callback.
  340. void setCallback(UnpackOptionsCallback callback) {
  341. callback_ = callback;
  342. }
  343. /// @brief copies relay information from client's packet to server's response
  344. ///
  345. /// This information is not simply copied over. Some parameter are
  346. /// removed, msg_type_is updated (RELAY-FORW => RELAY-REPL), etc.
  347. ///
  348. /// @param question client's packet
  349. void copyRelayInfo(const Pkt6Ptr& question);
  350. /// relay information
  351. ///
  352. /// this is a public field. Otherwise we hit one of the two problems:
  353. /// we return reference to an internal field (and that reference could
  354. /// be potentially used past Pkt6 object lifetime causing badness) or
  355. /// we return a copy (which is inefficient and also causes any updates
  356. /// to be impossible). Therefore public field is considered the best
  357. /// (or least bad) solution.
  358. std::vector<RelayInfo> relay_info_;
  359. /// unparsed data (in received packets)
  360. ///
  361. /// @warning This public member is accessed by derived
  362. /// classes directly. One of such derived classes is
  363. /// @ref perfdhcp::PerfPkt6. The impact on derived clasess'
  364. /// behavior must be taken into consideration before making
  365. /// changes to this member such as access scope restriction or
  366. /// data format change etc.
  367. OptionBuffer data_;
  368. protected:
  369. /// Builds on wire packet for TCP transmission.
  370. ///
  371. /// TODO This function is not implemented yet.
  372. ///
  373. /// @throw NotImplemented, IPv6 over TCP is not yet supported.
  374. void packTCP();
  375. /// Builds on wire packet for UDP transmission.
  376. ///
  377. /// @throw InvalidOperation if packing fails
  378. void packUDP();
  379. /// @brief Parses on-wire form of TCP DHCPv6 packet.
  380. ///
  381. /// Parses received packet, stored in on-wire format in data_.
  382. /// data_len_ must be set to indicate data length.
  383. /// Will create a collection of option objects that will
  384. /// be stored in options_ container.
  385. ///
  386. /// TODO This function is not implemented yet.
  387. ///
  388. /// @return true, if build was successful
  389. bool unpackTCP();
  390. /// @brief Parses on-wire form of UDP DHCPv6 packet.
  391. ///
  392. /// Parses received packet, stored in on-wire format in data_.
  393. /// data_len_ must be set to indicate data length.
  394. /// Will create a collection of option objects that will
  395. /// be stored in options_ container.
  396. ///
  397. /// @return true, if build was successful
  398. bool unpackUDP();
  399. /// @brief unpacks direct (non-relayed) message
  400. ///
  401. /// This method unpacks specified buffer range as a direct
  402. /// (e.g. solicit or request) message. This method is called from
  403. /// unpackUDP() when received message is detected to be direct.
  404. ///
  405. /// @param begin start of the buffer
  406. /// @param end end of the buffer
  407. /// @return true if parsing was successful and there are no leftover bytes
  408. bool unpackMsg(OptionBuffer::const_iterator begin,
  409. OptionBuffer::const_iterator end);
  410. /// @brief unpacks relayed message (RELAY-FORW or RELAY-REPL)
  411. ///
  412. /// This method is called from unpackUDP() when received message
  413. /// is detected to be relay-message. It goes iteratively over
  414. /// all relays (if there are multiple encapsulation levels).
  415. ///
  416. /// @return true if parsing was successful
  417. bool unpackRelayMsg();
  418. /// @brief calculates overhead introduced in specified relay
  419. ///
  420. /// It is used when calculating message size and packing message
  421. /// @param relay RelayInfo structure that holds information about relay
  422. /// @return number of bytes needed to store relay information
  423. uint16_t getRelayOverhead(const RelayInfo& relay) const;
  424. /// @brief calculates overhead for all relays defined for this message
  425. /// @return number of bytes needed to store all relay information
  426. uint16_t calculateRelaySizes();
  427. /// @brief calculates size of the message as if it was not relayed at all
  428. ///
  429. /// This is equal to len() if the message was not relayed.
  430. /// @return number of bytes required to store the message
  431. uint16_t directLen() const;
  432. /// UDP (usually) or TCP (bulk leasequery or failover)
  433. DHCPv6Proto proto_;
  434. /// DHCPv6 message type
  435. uint8_t msg_type_;
  436. /// DHCPv6 transaction-id
  437. uint32_t transid_;
  438. /// name of the network interface the packet was received/to be sent over
  439. std::string iface_;
  440. /// @brief interface index
  441. ///
  442. /// interface index (each network interface has assigned unique ifindex
  443. /// it is functional equivalent of name, but sometimes more useful, e.g.
  444. /// when using crazy systems that allow spaces in interface names
  445. /// e.g. windows
  446. int ifindex_;
  447. /// local address (dst if receiving packet, src if sending packet)
  448. isc::asiolink::IOAddress local_addr_;
  449. /// remote address (src if receiving packet, dst if sending packet)
  450. isc::asiolink::IOAddress remote_addr_;
  451. /// local TDP or UDP port
  452. uint16_t local_port_;
  453. /// remote TCP or UDP port
  454. uint16_t remote_port_;
  455. /// output buffer (used during message transmission)
  456. ///
  457. /// @warning This protected member is accessed by derived
  458. /// classes directly. One of such derived classes is
  459. /// @ref perfdhcp::PerfPkt6. The impact on derived clasess'
  460. /// behavior must be taken into consideration before making
  461. /// changes to this member such as access scope restriction or
  462. /// data format change etc.
  463. isc::util::OutputBuffer bufferOut_;
  464. /// packet timestamp
  465. boost::posix_time::ptime timestamp_;
  466. /// A callback to be called to unpack options from the packet.
  467. UnpackOptionsCallback callback_;
  468. }; // Pkt6 class
  469. } // isc::dhcp namespace
  470. } // isc namespace
  471. #endif