pkt6.h 21 KB

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