dhcp6_srv.h 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. // Copyright (C) 2011-2017 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #ifndef DHCPV6_SRV_H
  7. #define DHCPV6_SRV_H
  8. #include <asiolink/io_service.h>
  9. #include <dhcp_ddns/ncr_msg.h>
  10. #include <dhcp/dhcp6.h>
  11. #include <dhcp/duid.h>
  12. #include <dhcp/option.h>
  13. #include <dhcp/option6_client_fqdn.h>
  14. #include <dhcp/option6_ia.h>
  15. #include <dhcp/option_definition.h>
  16. #include <dhcp/pkt6.h>
  17. #include <dhcpsrv/alloc_engine.h>
  18. #include <dhcpsrv/cfg_option.h>
  19. #include <dhcpsrv/d2_client_mgr.h>
  20. #include <dhcpsrv/subnet.h>
  21. #include <hooks/callout_handle.h>
  22. #include <dhcpsrv/daemon.h>
  23. #include <iostream>
  24. #include <queue>
  25. // Undefine the macro OPTIONAL which is defined in some operating
  26. // systems but conflicts with a member of the RequirementLevel enum in
  27. // the server class.
  28. #ifdef OPTIONAL
  29. #undef OPTIONAL
  30. #endif
  31. namespace isc {
  32. namespace dhcp {
  33. /// @brief This exception is thrown when DHCP server hits the error which should
  34. /// result in discarding the message being processed.
  35. class DHCPv6DiscardMessageError : public Exception {
  36. public:
  37. DHCPv6DiscardMessageError(const char* file, size_t line, const char* what) :
  38. isc::Exception(file, line, what) { };
  39. };
  40. /// @brief DHCPv6 server service.
  41. ///
  42. /// This class represents DHCPv6 server. It contains all
  43. /// top-level methods and routines necessary for server operation.
  44. /// In particular, it instantiates IfaceMgr, loads or generates DUID
  45. /// that is going to be used as server-identifier, receives incoming
  46. /// packets, processes them, manages leases assignment and generates
  47. /// appropriate responses.
  48. class Dhcpv6Srv : public Daemon {
  49. private:
  50. /// @brief Pointer to IO service used by the server.
  51. asiolink::IOServicePtr io_service_;
  52. public:
  53. /// @brief defines if certain option may, must or must not appear
  54. typedef enum {
  55. FORBIDDEN,
  56. MANDATORY,
  57. OPTIONAL
  58. } RequirementLevel;
  59. /// @brief Minimum length of a MAC address to be used in DUID generation.
  60. static const size_t MIN_MAC_LEN = 6;
  61. /// @brief Default constructor.
  62. ///
  63. /// Instantiates necessary services, required to run DHCPv6 server.
  64. /// In particular, creates IfaceMgr that will be responsible for
  65. /// network interaction. Will instantiate lease manager, and load
  66. /// old or create new DUID.
  67. ///
  68. /// @param port port on will all sockets will listen
  69. Dhcpv6Srv(uint16_t port = DHCP6_SERVER_PORT);
  70. /// @brief Destructor. Used during DHCPv6 service shutdown.
  71. virtual ~Dhcpv6Srv();
  72. /// @brief Returns pointer to the IO service used by the server.
  73. asiolink::IOServicePtr& getIOService() {
  74. return (io_service_);
  75. }
  76. /// @brief returns Kea version on stdout and exit.
  77. /// redeclaration/redefinition. @ref Daemon::getVersion()
  78. static std::string getVersion(bool extended);
  79. /// @brief Returns server-identifier option.
  80. ///
  81. /// @return server-id option
  82. OptionPtr getServerID() { return serverid_; }
  83. /// @brief Main server processing loop.
  84. ///
  85. /// Main server processing loop. Call the processing step routine
  86. /// until shut down.
  87. ///
  88. /// @return true, if being shut down gracefully, never fail.
  89. bool run();
  90. /// @brief Main server processing step.
  91. ///
  92. /// Main server processing step. Receives one incoming packet, calls
  93. /// the processing packet routing and (if necessary) transmits
  94. /// a response.
  95. void run_one();
  96. /// @brief Process a single incoming DHCPv6 packet.
  97. ///
  98. /// It verifies correctness of the passed packet, call per-type processXXX
  99. /// methods, generates appropriate answer.
  100. ///
  101. /// @param query A pointer to the packet to be processed.
  102. /// @param rsp A pointer to the response
  103. void processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp);
  104. /// @brief Instructs the server to shut down.
  105. void shutdown();
  106. /// @brief Get UDP port on which server should listen.
  107. ///
  108. /// Typically, server listens on UDP port 547. Other ports are only
  109. /// used for testing purposes.
  110. ///
  111. /// @return UDP port on which server should listen.
  112. uint16_t getPort() const {
  113. return (port_);
  114. }
  115. /// @brief Starts DHCP_DDNS client IO if DDNS updates are enabled.
  116. ///
  117. /// If updates are enabled, it instructs the D2ClientMgr singleton to
  118. /// enter send mode. If D2ClientMgr encounters errors it may throw
  119. /// D2ClientError. This method does not catch exceptions.
  120. void startD2();
  121. /// @brief Stops DHCP_DDNS client IO if DDNS updates are enabled.
  122. ///
  123. /// If updates are enabled, it instructs the D2ClientMgr singleton to
  124. /// leave send mode. If D2ClientMgr encounters errors it may throw
  125. /// D2ClientError. This method does not catch exceptions.
  126. void stopD2();
  127. /// @brief Implements the error handler for DHCP_DDNS IO errors
  128. ///
  129. /// Invoked when a NameChangeRequest send to kea-dhcp-ddns completes with
  130. /// a failed status. These are communications errors, not data related
  131. /// failures.
  132. ///
  133. /// This method logs the failure and then suspends all further updates.
  134. /// Updating can only be restored by reconfiguration or restarting the
  135. /// server. There is currently no retry logic so the first IO error that
  136. /// occurs will suspend updates.
  137. /// @todo We may wish to make this more robust or sophisticated.
  138. ///
  139. /// @param result Result code of the send operation.
  140. /// @param ncr NameChangeRequest which failed to send.
  141. virtual void d2ClientErrorHandler(const dhcp_ddns::
  142. NameChangeSender::Result result,
  143. dhcp_ddns::NameChangeRequestPtr& ncr);
  144. protected:
  145. /// @brief Compare received server id with our server id
  146. ///
  147. /// Checks if the server id carried in a query from a client matches
  148. /// server identifier being used by the server.
  149. ///
  150. /// @param pkt DHCPv6 packet carrying server identifier to be checked.
  151. /// @return true if server id carried in the query matches server id
  152. /// used by the server; false otherwise.
  153. bool testServerID(const Pkt6Ptr& pkt);
  154. /// @brief Check if the message can be sent to unicast.
  155. ///
  156. /// This function checks if the received message conforms to the section 15
  157. /// of RFC3315 which says that: "A server MUST discard any Solicit, Confirm,
  158. /// Rebind or Information-request messages it receives with a unicast
  159. /// destination address.
  160. ///
  161. /// @param pkt DHCPv6 message to be checked.
  162. /// @return false if the message has been sent to unicast address but it is
  163. /// not allowed according to RFC3315, section 15; true otherwise.
  164. bool testUnicast(const Pkt6Ptr& pkt) const;
  165. /// @brief verifies if specified packet meets RFC requirements
  166. ///
  167. /// Checks if mandatory option is really there, that forbidden option
  168. /// is not there, and that client-id or server-id appears only once.
  169. ///
  170. /// @param pkt packet to be checked
  171. /// @param clientid expectation regarding client-id option
  172. /// @param serverid expectation regarding server-id option
  173. /// @throw RFCViolation if any issues are detected
  174. void sanityCheck(const Pkt6Ptr& pkt, RequirementLevel clientid,
  175. RequirementLevel serverid);
  176. /// @brief Processes incoming Solicit and returns response.
  177. ///
  178. /// Processes received Solicit message and verifies that its sender
  179. /// should be served. In particular IA, TA and PD options are populated
  180. /// with to-be assigned addresses, temporary addresses and delegated
  181. /// prefixes, respectively. In the usual 4 message exchange, server is
  182. /// expected to respond with Advertise message. However, if client
  183. /// requests rapid-commit and server supports it, Reply will be sent
  184. /// instead of Advertise and requested leases will be assigned
  185. /// immediately.
  186. ///
  187. /// @param solicit Solicit message received from client
  188. ///
  189. /// @return Advertise, Reply message or NULL.
  190. Pkt6Ptr processSolicit(const Pkt6Ptr& solicit);
  191. /// @brief Processes incoming Request and returns Reply response.
  192. ///
  193. /// Processes incoming Request message and verifies that its sender
  194. /// should be served. In particular IA, TA and PD options are populated
  195. /// with assigned addresses, temporary addresses and delegated
  196. /// prefixes, respectively. Uses LeaseMgr to allocate or update existing
  197. /// leases.
  198. ///
  199. /// @param request a message received from client
  200. ///
  201. /// @return REPLY message or NULL
  202. Pkt6Ptr processRequest(const Pkt6Ptr& request);
  203. /// @brief Processes incoming Renew message.
  204. ///
  205. /// @param renew message received from the client
  206. /// @return Reply message to be sent to the client.
  207. Pkt6Ptr processRenew(const Pkt6Ptr& renew);
  208. /// @brief Processes incoming Rebind message.
  209. ///
  210. /// @todo There are cases when the Rebind message should be discarded
  211. /// by the DHCP server. One of those is when the server doesn't have a
  212. /// record of the client and it is unable to determine whether the
  213. /// client is on the appropriate link or not. We don't seem to do it
  214. /// now.
  215. ///
  216. /// @param rebind message received from the client.
  217. /// @return Reply message to be sent to the client.
  218. Pkt6Ptr processRebind(const Pkt6Ptr& rebind);
  219. /// @brief Processes incoming Confirm message and returns Reply.
  220. ///
  221. /// This function processes Confirm message from the client according
  222. /// to section 18.2.2. of RFC3315. It discards the Confirm message if
  223. /// the message sent by the client contains no addresses, i.e. it has
  224. /// no IA_NA options or all IA_NA options contain no IAAddr options.
  225. ///
  226. /// If the Confirm message contains addresses this function will perform
  227. /// the following checks:
  228. /// - check if there is appropriate subnet configured for the client
  229. /// (e.g. subnet from which addresses are assigned for requests
  230. /// received on the particular interface).
  231. /// - check if all addresses sent in the Confirm message belong to the
  232. /// selected subnet.
  233. ///
  234. /// If any of the checks above fails, the Reply message with the status
  235. /// code NotOnLink is returned. Otherwise, the Reply message with the
  236. /// status code Success is returned.
  237. ///
  238. /// @param confirm Confirm message sent by a client.
  239. ///
  240. /// @return Reply message from the server or NULL pointer if Confirm
  241. /// message should be discarded by the server.
  242. Pkt6Ptr processConfirm(const Pkt6Ptr& confirm);
  243. /// @brief Process incoming Release message.
  244. ///
  245. /// @param release message received from client
  246. /// @return Reply message to be sent to the client.
  247. Pkt6Ptr processRelease(const Pkt6Ptr& release);
  248. /// @brief Process incoming Decline message.
  249. ///
  250. /// This method processes Decline message. It conducts standard sanity
  251. /// checks, creates empty reply and copies the necessary options from
  252. /// the client's message. Finally, it calls @ref declineLeases, where
  253. /// the actual address processing takes place.
  254. ///
  255. /// @throw RFCViolation if Decline message is invalid (lacking mandatory
  256. /// options)
  257. ///
  258. /// @param decline message received from client
  259. Pkt6Ptr processDecline(const Pkt6Ptr& decline);
  260. /// @brief Processes incoming Information-request message.
  261. ///
  262. /// @param inf_request message received from client
  263. /// @return Reply message to be sent to the client.
  264. Pkt6Ptr processInfRequest(const Pkt6Ptr& inf_request);
  265. /// @brief Processes incoming DHCPv4-query message.
  266. ///
  267. /// It always returns NULL, as there is nothing to be sent back to the
  268. /// client at this time. The message was sent to DHCPv4 server using
  269. /// @ref isc::dhcp::Dhcp6to4Ipc::handler()). We will send back a response
  270. /// to the client once we get back DHCP4-REPLY from the DHCPv4 server.
  271. ///
  272. /// @param dhcp4_query message received from client
  273. void processDhcp4Query(const Pkt6Ptr& dhcp4_query);
  274. /// @brief Selects a subnet for a given client's packet.
  275. ///
  276. /// @param question client's message
  277. /// @return selected subnet (or NULL if no suitable subnet was found)
  278. isc::dhcp::Subnet6Ptr selectSubnet(const Pkt6Ptr& question);
  279. /// @brief Processes IA_NA option (and assigns addresses if necessary).
  280. ///
  281. /// Generates response to IA_NA. This typically includes selecting (and
  282. /// allocating a lease in case of REQUEST) an address lease and creating
  283. /// IAADDR option. In case of allocation failure, it may contain
  284. /// status code option with non-zero status, denoting cause of the
  285. /// allocation failure.
  286. ///
  287. /// @param query client's message (typically SOLICIT or REQUEST)
  288. /// @param answer server's response to the client's message. This
  289. /// message should contain Client FQDN option being sent by the server
  290. /// to the client (if the client sent this option to the server).
  291. /// @param ctx client context (contains subnet, duid and other parameters)
  292. /// @param ia pointer to client's IA_NA option (client's request)
  293. ///
  294. /// @return IA_NA option (server's response)
  295. OptionPtr assignIA_NA(const isc::dhcp::Pkt6Ptr& query,
  296. const isc::dhcp::Pkt6Ptr& answer,
  297. AllocEngine::ClientContext6& ctx,
  298. Option6IAPtr ia);
  299. /// @brief Processes IA_PD option (and assigns prefixes if necessary).
  300. ///
  301. /// Generates response to IA_PD. This typically includes selecting (and
  302. /// allocating in the case of REQUEST) a prefix lease and creating an
  303. /// IAPREFIX option. In case of an allocation failure, it may contain a
  304. /// status code option with non-zero status denoting the cause of the
  305. /// allocation failure.
  306. ///
  307. /// @param query client's message (typically SOLICIT or REQUEST)
  308. /// @param answer server's response to the client's message.
  309. /// @param ctx client context (contains subnet, duid and other parameters)
  310. /// @param ia pointer to client's IA_PD option (client's request)
  311. /// @return IA_PD option (server's response)
  312. OptionPtr assignIA_PD(const Pkt6Ptr& query,
  313. const isc::dhcp::Pkt6Ptr& answer,
  314. AllocEngine::ClientContext6& ctx,
  315. boost::shared_ptr<Option6IA> ia);
  316. /// @brief Extends lifetime of the specific IA_NA option.
  317. ///
  318. /// Generates response to IA_NA in Renew or Rebind. This typically includes
  319. /// finding a lease that corresponds to the received address. If no such
  320. /// lease is found, an IA_NA response is generated with an appropriate
  321. /// status code.
  322. ///
  323. /// @todo The behavior of this function will need to be extended to support
  324. /// draft-ietf-dhc-dhcpv6-stateful-issues. This draft modifies the behavior
  325. /// described in RFC3315 with respect to Renew and Rebind processing. Key
  326. /// changes are (version -05):
  327. /// - Renewing and Rebinding client MAY request additional bindings by
  328. /// putting an IA for all bindings it desires but has been unable to obtain.
  329. /// Server MAY allocate addresses if it finds that they are appropriate for
  330. /// the link that client is attached to.
  331. /// - When receiving Rebind, if the server determines that the addresses are
  332. /// not appropriate for the link the client is attached to, the server MAY
  333. /// send the IA with address lifetimes set to 0 or discard the message.
  334. ///
  335. /// @param query client's message (Renew or Rebind)
  336. /// @param answer server's response to the client's message. This
  337. /// message should contain Client FQDN option being sent by the server
  338. /// to the client (if the client sent this option to the server).
  339. /// @param ctx client context (contains subnet, duid and other parameters)
  340. /// @param ia IA_NA option which carries address for which lease lifetime
  341. /// will be extended.
  342. /// @return IA_NA option (server's response)
  343. OptionPtr extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer,
  344. AllocEngine::ClientContext6& ctx,
  345. Option6IAPtr ia);
  346. /// @brief Extends lifetime of the prefix.
  347. ///
  348. /// This function is called by the logic which processes Renew and Rebind
  349. /// messages to extend the lifetime of the existing prefix.
  350. ///
  351. /// The behavior of this function is different in that when there is no
  352. /// binding found in the lease database for the particular client the
  353. /// NoBinding status code is returned when processing Renew, the exception
  354. /// is thrown when there is no binding and the Rebind message is processed
  355. /// (see RFC3633, section 12.2. for details).
  356. ///
  357. /// @param query client's message
  358. /// @param ctx client context (contains subnet, duid and other parameters)
  359. /// @param ia IA_PD option that is being renewed
  360. /// @return IA_PD option (server's response)
  361. /// @throw DHCPv6DiscardMessageError when the message being processed should
  362. /// be discarded by the server, i.e. there is no binding for the client doing
  363. /// Rebind.
  364. OptionPtr extendIA_PD(const Pkt6Ptr& query,
  365. AllocEngine::ClientContext6& ctx,
  366. Option6IAPtr ia);
  367. /// @brief Releases specific IA_NA option
  368. ///
  369. /// Generates response to IA_NA in Release message. This covers finding and
  370. /// removal of a lease that corresponds to the received address. If no such
  371. /// lease is found, an IA_NA response is generated with an appropriate
  372. /// status code.
  373. ///
  374. /// As RFC 3315 requires that a single status code be sent for the whole message,
  375. /// this method may update the passed general_status: it is set to SUCCESS when
  376. /// message processing begins, but may be updated to some error code if the
  377. /// release process fails.
  378. ///
  379. /// @param duid client's duid
  380. /// @param query client's message
  381. /// @param general_status a global status (it may be updated in case of errors)
  382. /// @param ia IA_NA option that is being released
  383. /// @return IA_NA option (server's response)
  384. OptionPtr releaseIA_NA(const DuidPtr& duid, const Pkt6Ptr& query,
  385. int& general_status,
  386. boost::shared_ptr<Option6IA> ia);
  387. /// @brief Releases specific IA_PD option
  388. ///
  389. /// Generates response to IA_PD in Release message. This covers finding and
  390. /// removal of a lease that corresponds to the received prefix(es). If no such
  391. /// lease is found, an IA_PD response is generated with an appropriate
  392. /// status code.
  393. ///
  394. /// @param duid client's duid
  395. /// @param query client's message
  396. /// @param general_status a global status (it may be updated in case of errors)
  397. /// @param ia IA_PD option that is being released
  398. /// @return IA_PD option (server's response)
  399. OptionPtr releaseIA_PD(const DuidPtr& duid, const Pkt6Ptr& query,
  400. int& general_status,
  401. boost::shared_ptr<Option6IA> ia);
  402. /// @brief Copies required options from client message to server answer.
  403. ///
  404. /// Copies options that must appear in any server response (ADVERTISE, REPLY)
  405. /// to client's messages (SOLICIT, REQUEST, RENEW, REBIND, DECLINE, RELEASE).
  406. /// One notable example is client-id. Other options may be copied as required.
  407. /// Relay information details are also copied here.
  408. ///
  409. /// @param question client's message (options will be copied from here)
  410. /// @param answer server's message (options will be copied here)
  411. void copyClientOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
  412. /// @brief Build the configured option list
  413. ///
  414. /// @note The configured option list is an *ordered* list of
  415. /// @c CfgOption objects used to append options to the response.
  416. ///
  417. /// @param question client's message
  418. /// @param ctx client context (for the subnet)
  419. /// @param co_list configured option list to build
  420. void buildCfgOptionList(const Pkt6Ptr& question,
  421. AllocEngine::ClientContext6& ctx,
  422. CfgOptionList& co_list);
  423. /// @brief Appends default options to server's answer.
  424. ///
  425. /// Adds required options to server's answer. In particular, server-id
  426. /// is added. Possibly other mandatory options will be added, depending
  427. /// on type (or content) of client message.
  428. ///
  429. /// @param question client's message
  430. /// @param answer server's message (options will be added here)
  431. /// @param co_list configured option list (currently unused)
  432. void appendDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
  433. const CfgOptionList& co_list);
  434. /// @brief Appends requested options to server's answer.
  435. ///
  436. /// Appends options requested by client to the server's answer.
  437. ///
  438. /// @param question client's message
  439. /// @param answer server's message (options will be added here)
  440. ///
  441. /// @param co_list configured option list
  442. void appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
  443. const CfgOptionList& co_list);
  444. /// @brief Appends requested vendor options to server's answer.
  445. ///
  446. /// This is mostly useful for Cable Labs options for now, but the method
  447. /// is easily extensible to other vendors.
  448. ///
  449. /// @param question client's message
  450. /// @param answer server's message (vendor options will be added here)
  451. /// @param ctx client context (contains subnet, duid and other parameters)
  452. /// @param co_list configured option list
  453. void appendRequestedVendorOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
  454. AllocEngine::ClientContext6& ctx,
  455. const CfgOptionList& co_list);
  456. /// @brief Assigns leases.
  457. ///
  458. /// It supports non-temporary addresses (IA_NA) and prefixes (IA_PD). It
  459. /// does NOT support temporary addresses (IA_TA).
  460. ///
  461. /// @param question client's message (with requested IA options)
  462. /// @param answer server's message (IA options will be added here).
  463. /// This message should contain Client FQDN option being sent by the server
  464. /// to the client (if the client sent this option to the server).
  465. /// @param ctx client context (contains subnet, duid and other parameters)
  466. void assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer,
  467. AllocEngine::ClientContext6& ctx);
  468. /// @brief Processes Client FQDN Option.
  469. ///
  470. /// This function retrieves DHCPv6 Client FQDN %Option (if any) from the
  471. /// packet sent by a client and takes necessary actions upon this option.
  472. /// Received option comprises flags field which controls what DNS updates
  473. /// server should do. Server may override client's preference based on
  474. /// the current configuration. Server indicates that it has overridden
  475. /// the preference by storing DHCPv6 Client FQDN option with the
  476. /// appropriate flags in the response to a client. This option is also
  477. /// used to communicate the client's domain-name which should be sent
  478. /// to the DNS in the update. Again, server may act upon the received
  479. /// domain-name, i.e. if the provided domain-name is partial it should
  480. /// generate the fully qualified domain-name.
  481. ///
  482. /// This function takes into account the host reservation if one is matched
  483. /// to this client when forming the FQDN to be used with DNS as well as the
  484. /// lease name to be stored with the lease. In the following the term
  485. /// "reserved hostname" means a host reservation which includes a
  486. /// non-blank hostname.
  487. ///
  488. /// - If there is no Client FQDN and no reserved hostname then there
  489. /// will no be DNS updates and the lease hostname will be empty.
  490. ///
  491. /// - If there is no Client FQDN but there is reserved hostname then
  492. /// there will be no DNS updates and the lease hostname will be equal
  493. /// to reserved hostname.
  494. ///
  495. /// - If there is a Client FQDN and a reserved hostname, then both the
  496. /// FQDN and lease hostname will be equal to reserved hostname with
  497. /// the qualifying suffix appended.
  498. ///
  499. /// - If there is a Client FQDN but no reserved hostname then both the
  500. /// FQDN and lease hostname will be equal to the name provided in the
  501. /// client FQDN adjusted according the the DhcpDdns configuration
  502. /// parameters (e.g.replace-client-name, qualifying suffix...).
  503. ///
  504. /// All the logic required to form appropriate answer to the client is
  505. /// held in this function.
  506. ///
  507. /// @param question Client's message.
  508. /// @param answer Server's response to a client. If server generated
  509. /// Client FQDN option for the client, this option is stored in this
  510. /// object.
  511. /// @param ctx client context (includes subnet, client-id, hw-addr etc.)
  512. void processClientFqdn(const Pkt6Ptr& question, const Pkt6Ptr& answer,
  513. AllocEngine::ClientContext6& ctx);
  514. /// @brief Creates a number of @c isc::dhcp_ddns::NameChangeRequest objects
  515. /// based on the DHCPv6 Client FQDN %Option.
  516. ///
  517. /// The @c isc::dhcp_ddns::NameChangeRequest class encapsulates the request
  518. /// from the DHCPv6 server to the DHCP-DDNS module to perform DNS Update.
  519. /// The FQDN option carries response to the client about DNS updates that
  520. /// server intends to perform for the DNS client. Based on this, the
  521. /// function will create zero or more @c isc::dhcp_ddns::NameChangeRequest
  522. /// objects and store them in the internal queue. Requests created by this
  523. /// function are only for adding or updating DNS records. If DNS updates are
  524. /// disabled, this method returns immediately.
  525. ///
  526. /// @todo Add support for multiple IAADDR options in the IA_NA.
  527. ///
  528. /// @param answer A message begins sent to the Client. If it holds the
  529. /// @param ctx client context (contains subnet, duid and other parameters)
  530. /// Client FQDN option, this option is used to create NameChangeRequests.
  531. void createNameChangeRequests(const Pkt6Ptr& answer,
  532. AllocEngine::ClientContext6& ctx);
  533. /// @brief Attempts to extend the lifetime of IAs.
  534. ///
  535. /// This function is called when a client sends Renew or Rebind message.
  536. /// It iterates through received IA options and attempts to extend
  537. /// corresponding lease lifetimes. Internally, it calls
  538. /// @c Dhcpv6Srv::extendIA_NA and @c Dhcpv6Srv::extendIA_PD to extend
  539. /// the lifetime of IA_NA and IA_PD leases accordingly.
  540. ///
  541. /// @param query client's Renew or Rebind message
  542. /// @param reply server's response
  543. /// @param ctx client context (contains subnet, duid and other parameters)
  544. void extendLeases(const Pkt6Ptr& query, Pkt6Ptr& reply,
  545. AllocEngine::ClientContext6& ctx);
  546. /// @brief Attempts to release received addresses
  547. ///
  548. /// It iterates through received IA_NA options and attempts to release
  549. /// received addresses. If no such leases are found, or the lease fails
  550. /// proper checks (e.g. belongs to someone else), a proper status
  551. /// code is added to reply message. Released addresses are not added
  552. /// to REPLY packet, just its IA_NA containers.
  553. /// @param release client's message asking to release
  554. /// @param reply server's response
  555. /// @param ctx client context (includes subnet, client-id, hw-addr etc.)
  556. void releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply,
  557. AllocEngine::ClientContext6& ctx);
  558. /// @brief converts DUID to text
  559. /// Converts content of DUID option to a text representation, e.g.
  560. /// 01:ff:02:03:06:80:90:ab:cd:ef
  561. ///
  562. /// @param opt option that contains DUID
  563. /// @return string representation
  564. static std::string duidToString(const OptionPtr& opt);
  565. /// @brief dummy wrapper around IfaceMgr::receive6
  566. ///
  567. /// This method is useful for testing purposes, where its replacement
  568. /// simulates reception of a packet. For that purpose it is protected.
  569. virtual Pkt6Ptr receivePacket(int timeout);
  570. /// @brief dummy wrapper around IfaceMgr::send()
  571. ///
  572. /// This method is useful for testing purposes, where its replacement
  573. /// simulates transmission of a packet. For that purpose it is protected.
  574. virtual void sendPacket(const Pkt6Ptr& pkt);
  575. /// @brief Assigns incoming packet to zero or more classes.
  576. ///
  577. /// @note This is done in two phases: first the content of the
  578. /// vendor-class-identifier option is used as a class, by
  579. /// calling @ref classifyByVendor(). Second classification match
  580. /// expressions are evaluated. The resulting classes will be stored
  581. /// in the packet (see @ref isc::dhcp::Pkt6::classes_ and
  582. /// @ref isc::dhcp::Pkt6::inClass).
  583. ///
  584. /// @param pkt packet to be classified
  585. void classifyPacket(const Pkt6Ptr& pkt);
  586. /// @brief Assigns classes retrieved from host reservation database.
  587. ///
  588. /// @param pkt Pointer to the packet to which classes will be assigned.
  589. /// @param ctx Reference to the client context.
  590. void setReservedClientClasses(const Pkt6Ptr& pkt,
  591. const AllocEngine::ClientContext6& ctx);
  592. /// @brief Attempts to get a MAC/hardware address using configred sources
  593. ///
  594. /// Tries to extract MAC/hardware address information from the packet
  595. /// using MAC sources configured in 'mac-sources' configuration parameter.
  596. ///
  597. /// @param pkt will try to exact MAC address from this packet
  598. /// @return HWaddr pointer (or NULL if configured methods fail)
  599. static HWAddrPtr getMAC(const Pkt6Ptr& pkt);
  600. /// @brief Processes Relay-supplied options, if present
  601. ///
  602. /// This method implements RFC6422. It checks if there are any RSOO options
  603. /// inserted by the relay agents in the query message. If there are, they
  604. /// are copied over to the response if they meet the following criteria:
  605. /// - the option is marked as RSOO-enabled (see relay-supplied-options
  606. /// configuration parameter)
  607. /// - there is no such option provided by the server)
  608. void processRSOO(const Pkt6Ptr& query, const Pkt6Ptr& rsp);
  609. /// @brief Initializes client context for specified packet
  610. ///
  611. /// This method:
  612. /// - Performs the subnet selection and stores the result in context
  613. /// - Extracts the duid from the packet and saves it to the context
  614. /// - Extracts the hardware address from the packet and saves it to
  615. /// the context
  616. /// - Performs host reservation lookup and stores the result in the
  617. /// context
  618. ///
  619. /// Even though the incoming packet type is known to this method, it
  620. /// doesn't set the @c fake_allocation flag, because of a possibility
  621. /// that the Rapid Commit option is in use. The @c fake_allocation
  622. /// flag is set appropriately after it has been determined whether
  623. /// the Rapid Commit option was included and that the server respects
  624. /// it.
  625. ///
  626. /// @param pkt pointer to a packet for which context will be created.
  627. /// @param [out] ctx reference to context object to be initialized.
  628. void initContext(const Pkt6Ptr& pkt, AllocEngine::ClientContext6& ctx);
  629. /// @brief this is a prefix added to the contend of vendor-class option
  630. ///
  631. /// If incoming packet has a vendor class option, its content is
  632. /// prepended with this prefix and then interpreted as a class.
  633. /// For example, a packet that sends vendor class with value of "FOO"
  634. /// will cause the packet to be assigned to class VENDOR_CLASS_FOO.
  635. static const std::string VENDOR_CLASS_PREFIX;
  636. /// @brief Attempts to decline all leases in specified Decline message.
  637. ///
  638. /// This method iterates over all IA_NA options and calls @ref declineIA on
  639. /// each of them.
  640. ///
  641. /// @param decline Decline message sent by a client
  642. /// @param reply Server's response (IA_NA with status will be added here)
  643. /// @param ctx context
  644. /// @return true when expected to continue, false when hooks told us to drop
  645. /// the packet
  646. bool declineLeases(const Pkt6Ptr& decline, Pkt6Ptr& reply,
  647. AllocEngine::ClientContext6& ctx);
  648. /// @brief Declines leases in a single IA_NA option
  649. ///
  650. /// This method iterates over all addresses in this IA_NA, verifies
  651. /// whether they belong to the client and calls @ref declineLease. If there's
  652. /// an error, general_status (a status put in the top level scope), will be
  653. /// updated.
  654. ///
  655. /// @param decline client's Decline message
  656. /// @param duid client's duid (used to verify if the client owns the lease)
  657. /// @param general_status [out] status in top-level message (may be updated)
  658. /// @param ia specific IA_NA option to process.
  659. /// @return IA_NA option with response (to be included in Reply message)
  660. OptionPtr
  661. declineIA(const Pkt6Ptr& decline, const DuidPtr& duid, int& general_status,
  662. boost::shared_ptr<Option6IA> ia);
  663. /// @brief Declines specific IPv6 lease.
  664. ///
  665. /// This method performs the actual decline and all necessary operations:
  666. /// - cleans up DNS, if necessary
  667. /// - updates subnet[X].declined-addresses (per subnet stat)
  668. /// - updates declined-addresses (global stat)
  669. /// - disassociates client information from the lease
  670. /// - moves the lease to DECLINED state
  671. /// - sets lease expiration time to decline-probation-period
  672. /// - adds status-code success
  673. ///
  674. /// @param decline used for generating removal Name Change Request.
  675. /// @param lease lease to be declined
  676. /// @param ia_rsp response IA_NA.
  677. /// @return true when expected to continue, false when hooks told us to drop
  678. /// the packet
  679. bool declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease,
  680. boost::shared_ptr<Option6IA> ia_rsp);
  681. /// @brief A simple utility method that sets the status code
  682. ///
  683. /// Removes old status code and sets a new one.
  684. /// @param container status code will be added here
  685. /// @param status status code option
  686. void setStatusCode(boost::shared_ptr<Option6IA>& container,
  687. const OptionPtr& status);
  688. private:
  689. /// @public
  690. /// @brief Assign class using vendor-class-identifier option
  691. ///
  692. /// @note This is the first part of @ref classifyPacket
  693. ///
  694. /// @param pkt packet to be classified
  695. /// @param classes a reference to added class names for logging
  696. void classifyByVendor(const Pkt6Ptr& pkt, std::string& classes);
  697. /// @private
  698. /// @brief Generate FQDN to be sent to a client if none exists.
  699. ///
  700. /// This function is meant to be called by the functions which process
  701. /// client's messages. The function should be called after a function
  702. /// which creates FQDN option for the client. This option must exist
  703. /// in the answer message specified as an argument. It must also be
  704. /// called after functions which assign leases for a client. The
  705. /// IA options being a result of lease acquisition must be appended
  706. /// to the message specified as a parameter.
  707. ///
  708. /// If the Client FQDN option being present in the message carries empty
  709. /// hostname, this function will attempt to generate hostname from the
  710. /// IPv6 address being acquired by the client. The IPv6 address is retrieved
  711. /// from the IA_NA option carried in the specified message. If multiple
  712. /// addresses are present in the particular IA_NA option or multiple IA_NA
  713. /// options exist, the first address found is selected.
  714. ///
  715. /// The IPv6 address is converted to the hostname using the following
  716. /// pattern:
  717. /// @code
  718. /// prefix-converted-ip-address.domain-name-suffix.
  719. /// @endcode
  720. /// where:
  721. /// - prefix is a configurable prefix string appended to all auto-generated
  722. /// hostnames.
  723. /// - converted-ip-address is created by replacing all colons from the IPv6
  724. /// address with hyphens.
  725. /// - domain-name-suffix is a suffix for a domain name that, together with
  726. /// the other parts, constitute the fully qualified domain name.
  727. ///
  728. /// When hostname is successfully generated, it is either used to update
  729. /// FQDN-related fields in a lease database or to update the Client FQDN
  730. /// option being sent back to the client. The lease database update is
  731. /// NOT performed if Advertise message is being processed.
  732. ///
  733. /// @param answer Message being sent to a client, which may hold IA_NA
  734. /// and Client FQDN options to be used to generate name for a client.
  735. ///
  736. /// @throw isc::Unexpected if specified message is NULL. This is treated
  737. /// as a programmatic error.
  738. void generateFqdn(const Pkt6Ptr& answer);
  739. /// @brief Updates statistics for received packets
  740. /// @param query packet received
  741. static void processStatsReceived(const Pkt6Ptr& query);
  742. /// @brief Checks if the specified option code has been requested using
  743. /// the Option Request option.
  744. ///
  745. /// @param query Pointer to the client's query.
  746. /// @parma code Option code.
  747. ///
  748. /// @return true if option has been requested in the ORO.
  749. bool requestedInORO(const Pkt6Ptr& query, const uint16_t code) const;
  750. /// UDP port number on which server listens.
  751. uint16_t port_;
  752. public:
  753. /// @note used by DHCPv4-over-DHCPv6 so must be public and static
  754. /// @brief Updates statistics for transmitted packets
  755. /// @param response packet transmitted
  756. static void processStatsSent(const Pkt6Ptr& response);
  757. /// @brief Returns the index of the buffer6_send hook
  758. /// @return the index of the buffer6_send hook
  759. static int getHookIndexBuffer6Send();
  760. protected:
  761. /// Server DUID (to be sent in server-identifier option)
  762. OptionPtr serverid_;
  763. /// Indicates if shutdown is in progress. Setting it to true will
  764. /// initiate server shutdown procedure.
  765. volatile bool shutdown_;
  766. /// @brief Allocation Engine.
  767. /// Pointer to the allocation engine that we are currently using
  768. /// It must be a pointer, because we will support changing engines
  769. /// during normal operation (e.g. to use different allocators)
  770. boost::shared_ptr<AllocEngine> alloc_engine_;
  771. /// Holds a list of @c isc::dhcp_ddns::NameChangeRequest objects, which
  772. /// are waiting for sending to kea-dhcp-ddns module.
  773. std::queue<isc::dhcp_ddns::NameChangeRequest> name_change_reqs_;
  774. };
  775. }; // namespace isc::dhcp
  776. }; // namespace isc
  777. #endif // DHCP6_SRV_H